KickJava   Java API By Example, From Geeks To Geeks.

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


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

8
9 package com.sleepycat.je.recovery;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.io.RandomAccessFile JavaDoc;
14 import java.util.Hashtable JavaDoc;
15 import java.util.List JavaDoc;
16
17 import com.sleepycat.je.Database;
18 import com.sleepycat.je.DatabaseConfig;
19 import com.sleepycat.je.DatabaseEntry;
20 import com.sleepycat.je.DbInternal;
21 import com.sleepycat.je.Environment;
22 import com.sleepycat.je.EnvironmentConfig;
23 import com.sleepycat.je.Transaction;
24 import com.sleepycat.je.config.EnvironmentParams;
25 import com.sleepycat.je.dbi.EnvironmentImpl;
26 import com.sleepycat.je.log.FileManager;
27 import com.sleepycat.je.tree.LN;
28 import com.sleepycat.je.tree.Node;
29 import com.sleepycat.je.util.StringDbt;
30 import com.sleepycat.je.util.TestUtils;
31
32 public class RecoveryEdgeTest extends RecoveryTestBase {
33     public void testNoLogFiles()
34         throws Throwable JavaDoc {
35
36         /* Creating an environment runs recovery. */
37         EnvironmentImpl env = null;
38         try {
39             EnvironmentConfig noFileConfig = TestUtils.initEnvConfig();
40             /* Don't checkpoint utilization info for this test. */
41             DbInternal.setCheckpointUP(noFileConfig, false);
42             noFileConfig.setConfigParam(EnvironmentParams.LOG_MEMORY_ONLY.getName(),
43                                         "true");
44             noFileConfig.setTransactional(true);
45             noFileConfig.setAllowCreate(true);
46             env = new EnvironmentImpl(envHome, noFileConfig);
47             List JavaDoc dbList = env.getDbMapTree().getDbNames();
48             assertEquals("no dbs exist", 0, dbList.size());
49
50             /* Fake a shutdown/startup. */
51             env.close();
52             env = new EnvironmentImpl(envHome, noFileConfig);
53             dbList = env.getDbMapTree().getDbNames();
54             assertEquals("no dbs exist", 0, dbList.size());
55         } catch (Throwable JavaDoc t) {
56             t.printStackTrace();
57             throw t;
58         } finally {
59             if (env != null)
60                 env.close();
61         }
62     }
63
64     /**
65      * Test setting of the database ids in recovery.
66      */

67     public void testDbId()
68         throws Throwable JavaDoc {
69
70         Transaction createTxn = null;
71         try {
72
73             /*
74              * Create an environment and three databases. The first two
75              * ids are allocated to the name db and the id db.
76              */

77             EnvironmentConfig createConfig = TestUtils.initEnvConfig();
78             createConfig.setTransactional(true);
79             createConfig.setAllowCreate(true);
80             createConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(), "6");
81             env = new Environment(envHome, createConfig);
82
83             int numStartDbs = 1;
84             createTxn = env.beginTransaction(null, null);
85
86             /* Check id of each db. */
87             DatabaseConfig dbConfig = new DatabaseConfig();
88             dbConfig.setTransactional(true);
89             dbConfig.setAllowCreate(true);
90             for (int i = 0; i < numStartDbs; i++) {
91                 Database anotherDb = env.openDatabase(createTxn, "foo" + i,
92                               dbConfig);
93                 assertEquals((i+3),
94                  DbInternal.dbGetDatabaseImpl(anotherDb).getId().getId());
95                 anotherDb.close();
96             }
97             createTxn.commit();
98             env.close();
99         
100             /*
101              * Go through a set of open, creates, and closes. Check id after
102              * recovery.
103              */

104             EnvironmentConfig envConfig = TestUtils.initEnvConfig();
105             envConfig.setTransactional(true);
106             createTxn = null;
107             for (int i = numStartDbs; i < numStartDbs + 3; i++) {
108                 env = new Environment(envHome, envConfig);
109
110                 createTxn = env.beginTransaction(null, null);
111                 Database anotherDb = env.openDatabase(createTxn, "foo" + i,
112                               dbConfig);
113                 assertEquals(i+3,
114                              DbInternal.dbGetDatabaseImpl(anotherDb).getId().getId());
115                 anotherDb.close();
116                 createTxn.commit();
117                 env.close();
118             }
119         } catch (Throwable JavaDoc t) {
120             if (createTxn != null) {
121                 createTxn.abort();
122             }
123             t.printStackTrace();
124             throw t;
125         }
126     }
127
128     /**
129      * Test setting the node ids in recovery.
130      */

131     public void testNodeId()
132         throws Throwable JavaDoc {
133
134         try {
135             /* Create an environment and databases. */
136             createEnvAndDbs(1024, true, NUM_DBS);
137             Hashtable JavaDoc expectedData = new Hashtable JavaDoc();
138             Transaction txn = env.beginTransaction(null, null);
139             insertData(txn, 0, 4, expectedData, 1, true, NUM_DBS);
140             txn.commit();
141
142             /* Find the largest node id that has been allocated. */
143             long maxSeenNodeId = Node.getLastId();
144
145             /* Close the environment, then recover. */
146             closeEnv();
147             EnvironmentConfig recoveryConfig = TestUtils.initEnvConfig();
148             recoveryConfig.setConfigParam(
149                            EnvironmentParams.NODE_MAX.getName(), "6");
150             recoveryConfig.setConfigParam(
151                            EnvironmentParams.ENV_RUN_CLEANER.getName(),
152                            "false");
153             /* Don't checkpoint utilization info for this test. */
154             DbInternal.setCheckpointUP(recoveryConfig, false);
155             env = new Environment(envHome, recoveryConfig);
156             LN ln = new LN(new byte[0]);
157             
158             /* Recovery should have initialized the next node id to use */
159             assertTrue(maxSeenNodeId + 1 < ln.getNodeId());
160             maxSeenNodeId = Node.getLastId();
161
162             /*
163              * One more time -- this recovery will get the node id off the
164              * checkpoint of the environment close. This checkpoint records
165              * the fact that the node id was bumped forward by the create of
166              * the LN above.
167              */

168             env.close();
169             env = new Environment(envHome, recoveryConfig);
170             ln = new LN(new byte[0]);
171             /*
172              * The environment re-opening will increment the node id
173              * several times because of the EOF node id.
174              */

175             assertTrue(maxSeenNodeId+1 <= ln.getNodeId());
176
177         } catch (Throwable JavaDoc t) {
178             t.printStackTrace();
179             throw t;
180         }
181     }
182
183     /**
184      * Test setting the txn id.
185      */

186     public void testTxnId()
187         throws Throwable JavaDoc {
188
189         try {
190             /* Create an environment and databases. */
191             createEnvAndDbs(1024, true, NUM_DBS);
192             Hashtable JavaDoc expectedData = new Hashtable JavaDoc();
193
194             /* Make txns before and after a checkpoint */
195             Transaction txn = env.beginTransaction(null, null);
196             insertData(txn, 0, 4, expectedData, 1, true, NUM_DBS);
197             txn.commit();
198             env.checkpoint(forceConfig);
199             txn = env.beginTransaction(null, null);
200             insertData(txn, 5, 6, expectedData, 1, false, NUM_DBS);
201
202             /* Find the largest node id that has been allocated. */
203             long maxTxnId = txn.getId();
204             txn.abort();
205
206             /* Close the environment, then recover. */
207             closeEnv();
208
209             EnvironmentConfig recoveryConfig = TestUtils.initEnvConfig();
210             recoveryConfig.setConfigParam (EnvironmentParams.ENV_RUN_CLEANER.getName(),
211                                            "false");
212             recoveryConfig.setTransactional(true);
213             env = new Environment(envHome, recoveryConfig);
214             
215             /*
216              * Check that the next txn id is larger than the last seen.
217              * A few txn ids were eaten by AutoTxns during recovery, do
218              * a basic check that we didn't eat more than 11.
219              */

220             txn = env.beginTransaction(null, null);
221             createDbs(txn, NUM_DBS);
222             assertTrue(maxTxnId < txn.getId());
223             assertTrue((txn.getId() - maxTxnId) < 11);
224
225             /*
226              * Do something with this txn so a node with it's value shows up in
227              * the log.
228              */

229             insertData(txn, 7, 8, expectedData, 1, false, NUM_DBS);
230             long secondMaxTxnId = txn.getId();
231             txn.abort();
232
233             /*
234              * One more time -- this recovery will get the txn id off the
235              * checkpoint of the second environment creation.
236              */

237             closeEnv();
238             env = new Environment(envHome, recoveryConfig);
239             txn = env.beginTransaction(null, null);
240             assertTrue(secondMaxTxnId < txn.getId());
241             assertTrue((txn.getId() - secondMaxTxnId) < 10);
242             txn.abort();
243         } catch (Throwable JavaDoc t) {
244             t.printStackTrace();
245             throw t;
246         }
247     }
248
249     /**
250      * Test writing a non-transactional db in a transactional environment.
251      * Make sure we can recover.
252      */

253     public void testNonTxnalDb ()
254         throws Throwable JavaDoc {
255
256         createEnv(1024, false);
257         try {
258             /*
259              * Create a database, write into it non-txnally. Should be
260              * allowed
261              */

262             DatabaseConfig dbConfig = new DatabaseConfig();
263             dbConfig.setAllowCreate(true);
264             Database dbA = env.openDatabase(null, "NotTxnal", dbConfig);
265
266             DatabaseEntry key = new StringDbt("foo");
267             DatabaseEntry data = new StringDbt("bar");
268             dbA.put(null, key, data);
269
270             /* close and recover -- the database should still be there
271              * because we're shutting down clean.
272              */

273             dbA.close();
274             env.close();
275             createEnv(1024, false);
276
277             dbA = env.openDatabase(null, "NotTxnal", null);
278             dbA.close();
279
280             /*
281              * Create a database, auto commit. Then write a record.
282              * The database should exist after recovery.
283              */

284             dbConfig.setTransactional(true);
285             Database dbB = env.openDatabase(null, "Txnal", dbConfig);
286             dbB.close();
287             dbB = env.openDatabase(null, "Txnal", null);
288             dbB.put(null, key, data);
289             dbB.close();
290             env.close();
291
292             /*
293              * Recover. We should see the database. We may or may not see
294              * the records.
295              */

296
297             createEnv(1024, false);
298             List JavaDoc dbNames = env.getDatabaseNames();
299             assertEquals(2, dbNames.size());
300             assertEquals("Txnal", dbNames.get(1));
301             assertEquals("NotTxnal", dbNames.get(0));
302             
303         } catch (Throwable JavaDoc t) {
304             t.printStackTrace();
305             throw t;
306         } finally {
307             env.close();
308         }
309     }
310
311     /**
312      * Test that we can recover with a bad checksum.
313      */

314     public void testBadChecksum()
315         throws Throwable JavaDoc {
316
317         try {
318             /* Create an environment and databases. */
319             createEnvAndDbs(2048, false, 1);
320             Hashtable JavaDoc expectedData = new Hashtable JavaDoc();
321
322             /* Make txns before and after a checkpoint */
323             Transaction txn = env.beginTransaction(null, null);
324             insertData(txn, 0, 4, expectedData, 1, true, 1);
325             txn.commit();
326             env.checkpoint(forceConfig);
327
328             txn = env.beginTransaction(null, null);
329             insertData(txn, 5, 6, expectedData, 1, true, 1);
330             txn.commit();
331
332             txn = env.beginTransaction(null, null);
333             insertData(txn, 7, 8, expectedData, 1, false, 1);
334
335             /* Close the environment, then recover. */
336             closeEnv();
337
338             /* Write some 0's into the last file. */
339             writeBadStuffInLastFile();
340
341             recoverAndVerify(expectedData, 1);
342         } catch (Throwable JavaDoc t) {
343             t.printStackTrace();
344             throw t;
345         }
346     }
347
348     /**
349      * Another bad checksum test. Make sure that there is no checkpoint in the
350      * last file so that this recovery will have to read backwards into the
351      * previous file. Also recover in read/only mode to make sure we don't
352      * process the bad portion of the log.
353      */

354     public void testBadChecksumReadOnlyReadPastLastFile()
355         throws Throwable JavaDoc {
356
357         try {
358             /* Create an environment and databases. */
359             createEnvAndDbs(500, false, 1);
360             Hashtable JavaDoc expectedData = new Hashtable JavaDoc();
361
362             /* Commit some data, checkpoint. */
363             Transaction txn = env.beginTransaction(null, null);
364             insertData(txn, 0, 4, expectedData, 1, true, 1);
365             txn.commit();
366             env.checkpoint(forceConfig);
367
368             /*
369              * Remember how many files we have, so we know where the last
370              * checkpoint is.
371              */

372             String JavaDoc [] suffixes = new String JavaDoc [] {FileManager.JE_SUFFIX};
373             String JavaDoc [] fileList = FileManager.listFiles(envHome, suffixes);
374             int startingNumFiles = fileList.length;
375
376             /* Now add enough non-committed data to add more files. */
377             txn = env.beginTransaction(null, null);
378             insertData(txn, 7, 50, expectedData, 1, false, 1);
379
380             /* Close the environment, then recover. */
381             closeEnv();
382
383             /* Make sure that we added on files after the checkpoint. */
384             fileList = FileManager.listFiles(envHome, suffixes);
385             assertTrue(fileList.length > startingNumFiles);
386
387             /* Write some 0's into the last file. */
388             writeBadStuffInLastFile();
389
390             recoverROAndVerify(expectedData, 1);
391         } catch (Throwable JavaDoc t) {
392             t.printStackTrace();
393             throw t;
394         }
395     }
396     
397     private void writeBadStuffInLastFile()
398         throws IOException JavaDoc {
399
400         String JavaDoc[] files =
401             FileManager.listFiles(envHome,
402                                   new String JavaDoc [] {FileManager.JE_SUFFIX});
403         File JavaDoc lastFile = new File JavaDoc(envHome, files[files.length - 1]);
404         RandomAccessFile JavaDoc rw = new RandomAccessFile JavaDoc(lastFile, "rw");
405
406         rw.seek(rw.length()-10);
407         rw.writeBytes("000000");
408         rw.close();
409     }
410 }
411
Popular Tags