KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > log > IOExceptionTest


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

8
9 package com.sleepycat.je.log;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.nio.ByteBuffer JavaDoc;
14
15 import junit.framework.TestCase;
16
17 import com.sleepycat.je.CheckpointConfig;
18 import com.sleepycat.je.Database;
19 import com.sleepycat.je.DatabaseConfig;
20 import com.sleepycat.je.DatabaseEntry;
21 import com.sleepycat.je.DatabaseException;
22 import com.sleepycat.je.DbInternal;
23 import com.sleepycat.je.Environment;
24 import com.sleepycat.je.EnvironmentConfig;
25 import com.sleepycat.je.EnvironmentStats;
26 import com.sleepycat.je.LockMode;
27 import com.sleepycat.je.OperationStatus;
28 import com.sleepycat.je.Transaction;
29 import com.sleepycat.je.config.EnvironmentParams;
30 import com.sleepycat.je.util.TestUtils;
31 import com.sleepycat.je.utilint.DbLsn;
32
33 public class IOExceptionTest extends TestCase {
34
35     private Environment env;
36     private Database db;
37     private File JavaDoc envHome;
38
39     public IOExceptionTest()
40         throws Exception JavaDoc {
41
42         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
43     }
44
45     public void setUp()
46         throws IOException JavaDoc, DatabaseException {
47
48         TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
49     }
50     
51     public void tearDown()
52         throws IOException JavaDoc, DatabaseException {
53
54     FileManager.IO_EXCEPTION_TESTING = false;
55     db.close();
56         env.close();
57         TestUtils.removeFiles("TearDown", envHome, FileManager.JE_SUFFIX);
58     }
59
60     public void testIOExceptionNoRecovery()
61     throws Throwable JavaDoc {
62
63     doIOExceptionTest(false);
64     }
65
66     public void testIOExceptionWithRecovery()
67     throws Throwable JavaDoc {
68
69     doIOExceptionTest(true);
70     }
71
72     public void testEviction()
73     throws Exception JavaDoc {
74
75     try {
76         createDatabase(200000, 0);
77     
78         final int N_RECS = 25;
79
80         CheckpointConfig chkConf = new CheckpointConfig();
81         chkConf.setForce(true);
82         Transaction txn = env.beginTransaction(null, null);
83         int keyInt = 0;
84         FileManager.IO_EXCEPTION_TESTING = true;
85         for (int i = 0; i < N_RECS; i++) {
86         String JavaDoc keyStr = Integer.toString(keyInt);
87         DatabaseEntry key =
88             new DatabaseEntry(keyStr.getBytes());
89         DatabaseEntry data =
90             new DatabaseEntry(("d" + keyStr).getBytes());
91         try {
92             assertTrue(db.put(txn, key, data) ==
93                    OperationStatus.SUCCESS);
94         } catch (DatabaseException DE) {
95             fail("unexpected DatabaseException");
96             break;
97         }
98         }
99
100         try {
101         env.checkpoint(chkConf);
102         fail("expected DatabaseException");
103         } catch (DatabaseException DE) {
104         }
105
106         EnvironmentStats stats = env.getStats(null);
107         assertTrue((stats.getNFullINFlush() +
108             stats.getNFullBINFlush()) > 0);
109
110         /* Read back the data and make sure it all looks ok. */
111         for (int i = 0; i < N_RECS; i++) {
112         String JavaDoc keyStr = Integer.toString(keyInt);
113         DatabaseEntry key =
114             new DatabaseEntry(keyStr.getBytes());
115         DatabaseEntry data = new DatabaseEntry();
116         try {
117             assertTrue(db.get(txn, key, data, null) ==
118                    OperationStatus.SUCCESS);
119             assertEquals(new String JavaDoc(data.getData()), "d" + keyStr);
120         } catch (DatabaseException DE) {
121             fail("unexpected DatabaseException");
122             break;
123         }
124         }
125
126         /*
127          * Now we have some IN's in the log buffer and there have been
128          * IOExceptions that will later force rewriting that buffer.
129          */

130         FileManager.IO_EXCEPTION_TESTING = false;
131         try {
132         txn.commit();
133         } catch (DatabaseException DE) {
134         fail("unexpected DatabaseException");
135         }
136     } catch (Exception JavaDoc E) {
137         E.printStackTrace();
138     }
139     }
140
141     /*
142      * Test for SR 13898. Write out some records with IO_EXCEPTION_TESTING
143      * true thereby forcing some commits to be rewritten as aborts. Ensure
144      * that the checksums are correct on those rewritten records by reading
145      * them back with a file reader.
146      */

147     public void testIOExceptionReadBack()
148     throws Exception JavaDoc {
149
150     try {
151         createDatabase(100000, 1000);
152     
153         final int N_RECS = 25;
154
155         CheckpointConfig chkConf = new CheckpointConfig();
156         chkConf.setForce(true);
157         Transaction txn = env.beginTransaction(null, null);
158         int keyInt = 0;
159         for (int i = 0; i < N_RECS; i++) {
160         String JavaDoc keyStr = Integer.toString(i);
161         DatabaseEntry key =
162             new DatabaseEntry(keyStr.getBytes());
163         DatabaseEntry data =
164             new DatabaseEntry(new byte[100]);
165         try {
166             assertTrue(db.put(txn, key, data) ==
167                    OperationStatus.SUCCESS);
168         } catch (DatabaseException DE) {
169             fail("unexpected DatabaseException");
170             break;
171         }
172         try {
173             FileManager.IO_EXCEPTION_TESTING = true;
174             txn.commit();
175             fail("expected DatabaseException");
176         } catch (DatabaseException DE) {
177         }
178         FileManager.IO_EXCEPTION_TESTING = false;
179         txn = env.beginTransaction(null, null);
180         }
181
182         FileManager.IO_EXCEPTION_TESTING = false;
183         try {
184         env.checkpoint(chkConf);
185         } catch (DatabaseException DE) {
186         DE.printStackTrace();
187         fail("unexpected DatabaseException");
188         }
189
190         EnvironmentStats stats = env.getStats(null);
191         assertTrue((stats.getNFullINFlush() +
192             stats.getNFullBINFlush()) > 0);
193         long lastCheckpointLsn = stats.getLastCheckpointStart();
194
195         try {
196         txn.commit();
197         } catch (DatabaseException DE) {
198         fail("unexpected DatabaseException");
199         }
200
201         FileReader reader = new FileReader
202         (DbInternal.envGetEnvironmentImpl(env),
203          4096, true, 0, null, DbLsn.NULL_LSN, DbLsn.NULL_LSN) {
204             protected boolean processEntry(ByteBuffer JavaDoc entryBuffer)
205             throws DatabaseException {
206
207             entryBuffer.position(entryBuffer.position() +
208                          currentEntrySize);
209             return true;
210             }
211         };
212
213         while (reader.readNextEntry()) {
214         }
215     } catch (Throwable JavaDoc E) {
216         E.printStackTrace();
217     }
218     }
219
220     public void testLogBufferOverflowAbortNoDupes()
221     throws Exception JavaDoc {
222
223     doLogBufferOverflowTest(false, false);
224     }
225
226     public void testLogBufferOverflowCommitNoDupes()
227     throws Exception JavaDoc {
228
229     doLogBufferOverflowTest(true, false);
230     }
231
232     public void testLogBufferOverflowAbortDupes()
233     throws Exception JavaDoc {
234
235     doLogBufferOverflowTest(false, true);
236     }
237
238     public void testLogBufferOverflowCommitDupes()
239     throws Exception JavaDoc {
240
241     doLogBufferOverflowTest(true, true);
242     }
243
244     private void doLogBufferOverflowTest(boolean abort, boolean dupes)
245     throws Exception JavaDoc {
246
247     try {
248         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
249         envConfig.setTransactional(true);
250         envConfig.setAllowCreate(true);
251         envConfig.setCacheSize(100000);
252         envConfig.setConfigParam("java.util.logging.level", "OFF");
253         env = new Environment(envHome, envConfig);
254
255         String JavaDoc databaseName = "ioexceptiondb";
256         DatabaseConfig dbConfig = new DatabaseConfig();
257         dbConfig.setAllowCreate(true);
258         dbConfig.setSortedDuplicates(true);
259         dbConfig.setTransactional(true);
260         db = env.openDatabase(null, databaseName, dbConfig);
261     
262         Transaction txn = env.beginTransaction(null, null);
263         DatabaseEntry oneKey =
264         (dupes ?
265          new DatabaseEntry("2".getBytes()) :
266          new DatabaseEntry("1".getBytes()));
267         DatabaseEntry oneData =
268         new DatabaseEntry(new byte[10]);
269         DatabaseEntry twoKey =
270         new DatabaseEntry("2".getBytes());
271         DatabaseEntry twoData =
272         new DatabaseEntry(new byte[100000]);
273         if (dupes) {
274         DatabaseEntry temp = oneKey;
275         oneKey = oneData;
276         oneData = temp;
277         temp = twoKey;
278         twoKey = twoData;
279         twoData = temp;
280         }
281
282         try {
283         assertTrue(db.put(txn, oneKey, oneData) ==
284                OperationStatus.SUCCESS);
285         db.put(txn, twoKey, twoData);
286         } catch (DatabaseException DE) {
287         fail("unexpected DatabaseException");
288         }
289
290         /* Read back the data and make sure it all looks ok. */
291         try {
292         assertTrue(db.get(txn, oneKey, oneData, null) ==
293                OperationStatus.SUCCESS);
294         assertTrue(oneData.getData().length == (dupes ? 1 : 10));
295         } catch (DatabaseException DE) {
296         fail("unexpected DatabaseException");
297         }
298
299         try {
300         assertTrue(db.get(txn, twoKey, twoData, null) ==
301                OperationStatus.SUCCESS);
302         } catch (DatabaseException DE) {
303         fail("unexpected DatabaseException");
304         }
305
306         try {
307         if (abort) {
308             txn.abort();
309         } else {
310             txn.commit();
311         }
312         } catch (DatabaseException DE) {
313         fail("unexpected DatabaseException");
314         }
315
316         /* Read back the data and make sure it all looks ok. */
317         try {
318         assertTrue(db.get(null, oneKey, oneData, null) ==
319                (abort ?
320                 OperationStatus.NOTFOUND :
321                 OperationStatus.SUCCESS));
322         assertTrue(oneData.getData().length == (dupes ? 1 : 10));
323         } catch (DatabaseException DE) {
324         fail("unexpected DatabaseException");
325         }
326
327         try {
328         assertTrue(db.get(null, twoKey, twoData, null) ==
329                (abort ?
330                 OperationStatus.NOTFOUND :
331                 OperationStatus.SUCCESS));
332         } catch (DatabaseException DE) {
333         fail("unexpected DatabaseException");
334         }
335
336     } catch (Exception JavaDoc E) {
337         E.printStackTrace();
338     }
339     }
340
341     public void testPutTransactionalWithIOException()
342     throws Throwable JavaDoc {
343
344     try {
345         createDatabase(100000, 0);
346
347         Transaction txn = env.beginTransaction(null, null);
348         int keyInt = 0;
349         String JavaDoc keyStr;
350         FileManager.IO_EXCEPTION_TESTING = true;
351
352         /* Fill up the buffer until we see an IOException. */
353         while (true) {
354         keyStr = Integer.toString(++keyInt);
355         DatabaseEntry key = new DatabaseEntry(keyStr.getBytes());
356         DatabaseEntry data =
357             new DatabaseEntry(("d" + keyStr).getBytes());
358         try {
359             assertTrue(db.put(txn, key, data) ==
360                    OperationStatus.SUCCESS);
361         } catch (DatabaseException DE) {
362             break;
363         }
364         }
365
366         /* Buffer still hasn't been written. This should also fail. */
367         try {
368         db.put(txn,
369                new DatabaseEntry("shouldFail".getBytes()),
370                new DatabaseEntry("shouldFailD".getBytes()));
371         fail("expected DatabaseException");
372         } catch (DatabaseException DE) {
373         // expected
374
}
375         FileManager.IO_EXCEPTION_TESTING = false;
376
377         /* Buffer should write out ok now. */
378         try {
379         db.put(txn,
380                new DatabaseEntry("shouldNotFail".getBytes()),
381                new DatabaseEntry("shouldNotFailD".getBytes()));
382         } catch (DatabaseException DE) {
383         fail("unexpected DatabaseException");
384         }
385         txn.commit();
386
387         DatabaseEntry data = new DatabaseEntry();
388         assertTrue(db.get(null,
389                   new DatabaseEntry("shouldNotFail".getBytes()),
390                   data,
391                   null) == OperationStatus.SUCCESS);
392         assertTrue(new String JavaDoc(data.getData()).equals("shouldNotFailD"));
393
394         assertTrue(db.get(null,
395                   new DatabaseEntry("shouldFail".getBytes()),
396                   data,
397                   null) == OperationStatus.NOTFOUND);
398
399         assertTrue(db.get(null,
400                   new DatabaseEntry("shouldFail".getBytes()),
401                   data,
402                   null) == OperationStatus.NOTFOUND);
403
404         assertTrue(db.get(null,
405                   new DatabaseEntry(keyStr.getBytes()),
406                   data,
407                   null) == OperationStatus.NOTFOUND);
408
409         for (int i = --keyInt; i > 0; i--) {
410         keyStr = Integer.toString(i);
411         assertTrue(db.get(null,
412                   new DatabaseEntry(keyStr.getBytes()),
413                   data,
414                   null) == OperationStatus.SUCCESS);
415         assertTrue(new String JavaDoc(data.getData()).equals("d" + keyStr));
416         }
417
418     } catch (Throwable JavaDoc T) {
419         T.printStackTrace();
420     }
421     }
422
423     private void doIOExceptionTest(boolean doRecovery)
424     throws Throwable JavaDoc {
425
426     Transaction txn = null;
427     createDatabase(0, 0);
428     writeAndVerify(null, false, "k1", "d1", doRecovery);
429     writeAndVerify(null, true, "k2", "d2", doRecovery);
430     writeAndVerify(null, false, "k3", "d3", doRecovery);
431
432     txn = env.beginTransaction(null, null);
433     writeAndVerify(txn, false, "k4", "d4", false);
434     txn.abort();
435     verify(null, true, "k4", doRecovery);
436     verify(null, false, "k1", doRecovery);
437     verify(null, false, "k3", doRecovery);
438
439     txn = env.beginTransaction(null, null);
440     writeAndVerify(txn, false, "k4", "d4", false);
441     txn.commit();
442     verify(null, false, "k4", doRecovery);
443
444     txn = env.beginTransaction(null, null);
445     writeAndVerify(txn, true, "k5", "d5", false);
446     /* Ensure that writes after IOExceptions don't succeed. */
447     writeAndVerify(txn, false, "k5a", "d5a", false);
448     txn.abort();
449     verify(null, true, "k5", doRecovery);
450     verify(null, true, "k5a", doRecovery);
451
452     txn = env.beginTransaction(null, null);
453     writeAndVerify(txn, false, "k6", "d6", false);
454     writeAndVerify(txn, true, "k6a", "d6a", false);
455
456     FileManager.IO_EXCEPTION_TESTING = true;
457     try {
458         txn.commit();
459         fail("expected DatabaseException");
460     } catch (DatabaseException DE) {
461     }
462     verify(null, true, "k6", doRecovery);
463     verify(null, true, "k6a", doRecovery);
464
465     txn = env.beginTransaction(null, null);
466     writeAndVerify(txn, false, "k6", "d6", false);
467     writeAndVerify(txn, true, "k6a", "d6a", false);
468     writeAndVerify(txn, false, "k6b", "d6b", false);
469
470     try {
471         txn.commit();
472     } catch (DatabaseException DE) {
473         fail("expected success");
474     }
475
476     /*
477      * k6a will still exist because the writeAndVerify didn't fail -- there
478      * was no write. The write happens at commit time.
479      */

480     verify(null, false, "k6", doRecovery);
481     verify(null, false, "k6a", doRecovery);
482     verify(null, false, "k6b", doRecovery);
483     }
484
485     private void writeAndVerify(Transaction txn,
486                 boolean throwIOException,
487                 String JavaDoc keyString,
488                 String JavaDoc dataString,
489                 boolean doRecovery)
490     throws DatabaseException {
491
492     //System.out.println("Key: " + keyString + " Data: " + dataString);
493
DatabaseEntry key = new DatabaseEntry(keyString.getBytes());
494     DatabaseEntry data = new DatabaseEntry(dataString.getBytes());
495     FileManager.IO_EXCEPTION_TESTING = throwIOException;
496     try {
497         assertTrue(db.put(txn, key, data) == OperationStatus.SUCCESS);
498
499         /*
500          * We don't expect an IOException if we're in a transaction because
501          * the put() only writes to the buffer, not the disk. The write to
502          * disk doesn't happen until the commit/abort.
503          */

504         if (throwIOException && txn == null) {
505         fail("didn't catch DatabaseException.");
506         }
507     } catch (DatabaseException DE) {
508         if (!throwIOException) {
509         fail("caught DatabaseException.");
510         }
511     }
512     verify(txn, throwIOException, keyString, doRecovery);
513     }
514
515     private void verify(Transaction txn,
516             boolean expectFailure,
517             String JavaDoc keyString,
518             boolean doRecovery)
519     throws DatabaseException {
520
521     if (doRecovery) {
522         db.close();
523         forceCloseEnvOnly();
524         createDatabase(0, 0);
525     }
526     DatabaseEntry key = new DatabaseEntry(keyString.getBytes());
527     DatabaseEntry returnedData = new DatabaseEntry();
528     OperationStatus status =
529         db.get(txn,
530            key,
531            returnedData,
532            LockMode.DEFAULT);
533     //System.out.println(keyString + " => " + status);
534
assertTrue(status == ((expectFailure && txn == null) ?
535                   OperationStatus.NOTFOUND :
536                   OperationStatus.SUCCESS));
537     }
538
539     private void createDatabase(long cacheSize, long maxFileSize)
540     throws DatabaseException {
541
542         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
543         envConfig.setTransactional(true);
544         envConfig.setAllowCreate(true);
545     envConfig.setConfigParam
546         (EnvironmentParams.NUM_LOG_BUFFERS.getName(), "2");
547     envConfig.setConfigParam
548         (EnvironmentParams.LOG_MEM_SIZE.getName(),
549          EnvironmentParams.LOG_MEM_SIZE_MIN_STRING);
550     if (maxFileSize != 0) {
551         DbInternal.disableParameterValidation(envConfig);
552         envConfig.setConfigParam
553         (EnvironmentParams.LOG_FILE_MAX.getName(), "" + maxFileSize);
554     }
555     if (cacheSize != 0) {
556         envConfig.setCacheSize(cacheSize);
557         envConfig.setConfigParam("java.util.logging.level", "OFF");
558     }
559     env = new Environment(envHome, envConfig);
560
561         String JavaDoc databaseName = "ioexceptiondb";
562         DatabaseConfig dbConfig = new DatabaseConfig();
563         dbConfig.setAllowCreate(true);
564         dbConfig.setSortedDuplicates(true);
565     dbConfig.setTransactional(true);
566         db = env.openDatabase(null, databaseName, dbConfig);
567     }
568
569     /* Force the environment to be closed even with outstanding handles.*/
570     private void forceCloseEnvOnly()
571     throws DatabaseException {
572
573     /* Close w/out checkpointing, in order to exercise recovery better.*/
574     try {
575         DbInternal.envGetEnvironmentImpl(env).close(false);
576     } catch (DatabaseException DE) {
577         if (!FileManager.IO_EXCEPTION_TESTING) {
578         throw DE;
579         } else {
580         /* Expect an exception from flushing the log manager. */
581         }
582     }
583     env = null;
584     }
585 }
586
Popular Tags