KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: LastFileReaderTest.java,v 1.66 2006/10/30 21:14:47 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.io.RandomAccessFile JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.Arrays JavaDoc;
16 import java.util.List JavaDoc;
17
18 import junit.framework.TestCase;
19
20 import com.sleepycat.je.DatabaseException;
21 import com.sleepycat.je.DbInternal;
22 import com.sleepycat.je.EnvironmentConfig;
23 import com.sleepycat.je.config.EnvironmentParams;
24 import com.sleepycat.je.dbi.DbConfigManager;
25 import com.sleepycat.je.dbi.EnvironmentImpl;
26 import com.sleepycat.je.tree.LN;
27 import com.sleepycat.je.util.BadFileFilter;
28 import com.sleepycat.je.util.TestUtils;
29 import com.sleepycat.je.utilint.DbLsn;
30 import com.sleepycat.je.utilint.Tracer;
31
32 public class LastFileReaderTest extends TestCase {
33
34     private DbConfigManager configManager;
35     private FileManager fileManager;
36     private LogManager logManager;
37     private File JavaDoc envHome;
38     private EnvironmentImpl envImpl;
39     public LastFileReaderTest() {
40         super();
41         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
42     }
43
44     public void setUp()
45         throws DatabaseException, IOException JavaDoc {
46
47         TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
48         TestUtils.removeFiles(envHome, new BadFileFilter());
49     }
50
51     public void tearDown()
52         throws DatabaseException, IOException JavaDoc {
53
54         /*
55          * Pass false to skip checkpoint, since the file manager may hold an
56          * open file that we've trashed in the tests, so we don't want to
57          * write to it here.
58          */

59         try {
60             envImpl.close(false);
61         } catch (DatabaseException e) {
62         }
63
64         TestUtils.removeFiles("TearDown", envHome, FileManager.JE_SUFFIX);
65         TestUtils.removeFiles(envHome, new BadFileFilter());
66     }
67
68     /* Create an environment, using the default log file size. */
69     private void initEnv()
70         throws DatabaseException {
71
72         initEnv(null);
73     }
74
75     /* Create an environment, specifying the log file size. */
76     private void initEnv(String JavaDoc logFileSize)
77         throws DatabaseException {
78
79         EnvironmentConfig envConfig = TestUtils.initEnvConfig();
80
81         /* Don't run daemons; we do some abrupt shutdowns. */
82         envConfig.setConfigParam
83             (EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
84         envConfig.setConfigParam
85             (EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
86         envConfig.setConfigParam
87             (EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
88
89         envConfig.setConfigParam
90         (EnvironmentParams.NODE_MAX.getName(), "6");
91     envConfig.setConfigParam
92         (EnvironmentParams.JE_LOGGING_LEVEL.getName(), "CONFIG");
93         if (logFileSize != null) {
94         DbInternal.disableParameterValidation(envConfig);
95             envConfig.setConfigParam
96                 (EnvironmentParams.LOG_FILE_MAX.getName(), logFileSize);
97         }
98
99         /* Disable noisy UtilizationProfile database creation. */
100         DbInternal.setCreateUP(envConfig, false);
101         /* Don't checkpoint utilization info for this test. */
102         DbInternal.setCheckpointUP(envConfig, false);
103
104     envConfig.setAllowCreate(true);
105         envImpl = new EnvironmentImpl(envHome, envConfig);
106         configManager = envImpl.getConfigManager();
107         fileManager = envImpl.getFileManager();
108         logManager = envImpl.getLogManager();
109     }
110
111     /**
112      * Run with an empty file that has a file header but no log entries.
113      */

114     public void testEmptyAtEnd()
115         throws Throwable JavaDoc {
116
117         initEnv();
118
119         /*
120          * Make a log file with a valid header, but no data.
121          */

122         FileManagerTestUtils.createLogFile(fileManager, envImpl, 100);
123         fileManager.clear();
124
125         LastFileReader reader = new LastFileReader(envImpl, 1000);
126         assertTrue(reader.readNextEntry());
127         assertEquals(0, DbLsn.getFileOffset(reader.getLastLsn()));
128     }
129
130     /**
131      * Run with an empty, 0 length file at the end. This has caused a
132      * BufferUnderflowException. [#SR 12631]
133      */

134     public void testLastFileEmpty()
135         throws Throwable JavaDoc {
136
137         initEnv("1000");
138         int numIters = 10;
139         List JavaDoc testObjs = new ArrayList JavaDoc();
140         List JavaDoc testLsns = new ArrayList JavaDoc();
141
142         /*
143          * Create a log with one or more files. Use only Tracer objects so we
144          * can iterate through the entire log ... ?
145          */

146         for (int i = 0; i < numIters; i++) {
147             /* Add a debug record. */
148             LoggableObject loggableObj =
149                 new Tracer("Hello there, rec " + (i+1));
150             testObjs.add(loggableObj);
151             testLsns.add(new Long JavaDoc(logManager.log(loggableObj)));
152         }
153         /* Flush the log, files. */
154     logManager.flush();
155         fileManager.clear();
156
157         int lastFileNum = fileManager.getAllFileNumbers().length - 1;
158
159         /*
160          * Create an extra, totally empty file.
161          */

162         fileManager.syncLogEnd();
163         fileManager.clear();
164         String JavaDoc emptyLastFile = fileManager.getFullFileName(lastFileNum+1,
165                                                       FileManager.JE_SUFFIX);
166
167         RandomAccessFile JavaDoc file =
168             new RandomAccessFile JavaDoc(emptyLastFile, FileManager.FileMode.
169                                  READWRITE_MODE.getModeValue());
170         file.close();
171
172         assertTrue(fileManager.getAllFileNumbers().length >= 2);
173
174         /*
175          * Try a LastFileReader. It should give us a end-of-log position in the
176          * penultimate file.
177          */

178         LastFileReader reader = new LastFileReader(envImpl, 1000);
179         while (reader.readNextEntry()) {
180         }
181
182         /*
183          * The reader should be positioned at the last, valid file, skipping
184          * this 0 length file.
185          */

186         assertEquals("lastValid=" + DbLsn.toString(reader.getLastValidLsn()),
187                      lastFileNum,
188                      DbLsn.getFileNumber(reader.getLastValidLsn()));
189         assertEquals(lastFileNum, DbLsn.getFileNumber(reader.getEndOfLog()));
190     }
191
192     /**
193      * Corrupt the file headers of the one and only log file.
194      */

195     public void testBadFileHeader()
196     throws Throwable JavaDoc {
197
198         initEnv();
199
200         /*
201          * Handle a log file that has data and a bad header. First corrupt the
202          * existing log file. We will not be able to establish log end, but
203          * won't throw away the file because it has data.
204          */

205         long lastFileNum = fileManager.getLastFileNum().longValue();
206         String JavaDoc lastFile =
207             fileManager.getFullFileName(lastFileNum,
208                                         FileManager.JE_SUFFIX);
209
210         RandomAccessFile JavaDoc file =
211             new RandomAccessFile JavaDoc(lastFile, FileManager.FileMode.
212                                  READWRITE_MODE.getModeValue());
213
214         file.seek(15);
215         file.writeBytes("putting more junk in, mess up header");
216         file.close();
217
218         /*
219          * We should see an exception on this one, because we made a file that
220          * looks like it has a bad header and bad data.
221          */

222         try {
223             LastFileReader reader = new LastFileReader(envImpl, 1000);
224             fail("Should see exception when creating " + reader);
225         } catch (DbChecksumException e) {
226             /* Eat exception, expected. */
227         }
228
229         /*
230          * Now make a bad file header, but one that is less than the size of a
231          * file header. This file ought to get moved aside.
232          */

233         file = new RandomAccessFile JavaDoc(lastFile, "rw");
234         file.getChannel().truncate(0);
235         file.writeBytes("bad");
236         file.close();
237
238         LastFileReader reader = new LastFileReader(envImpl, 1000);
239         /* Nothing comes back from reader. */
240         assertFalse(reader.readNextEntry());
241         File JavaDoc movedFile = new File JavaDoc(envHome, "00000000.bad");
242         assertTrue(movedFile.exists());
243
244         /* Try a few more times, we ought to keep moving the file. */
245         file = new RandomAccessFile JavaDoc(lastFile, "rw");
246         file.getChannel().truncate(0);
247         file.writeBytes("bad");
248         file.close();
249
250         reader = new LastFileReader(envImpl, 1000);
251         assertTrue(movedFile.exists());
252         File JavaDoc movedFile1 = new File JavaDoc(envHome, "00000000.bad.1");
253         assertTrue(movedFile1.exists());
254     }
255
256     /**
257      * Run with defaults.
258      */

259     public void testBasic()
260         throws Throwable JavaDoc {
261
262         initEnv();
263         int numIters = 50;
264         List JavaDoc testObjs = new ArrayList JavaDoc();
265         List JavaDoc testLsns = new ArrayList JavaDoc();
266
267         fillLogFile(numIters, testLsns, testObjs);
268         LastFileReader reader =
269             new LastFileReader(envImpl,
270                                configManager.getInt
271                                (EnvironmentParams.LOG_ITERATOR_READ_SIZE));
272
273         checkLogEnd(reader, numIters, testLsns, testObjs);
274     }
275
276     /**
277      * Run with very small read buffer.
278      */

279     public void testSmallBuffers()
280         throws Throwable JavaDoc {
281
282         initEnv();
283         int numIters = 50;
284         List JavaDoc testObjs = new ArrayList JavaDoc();
285         List JavaDoc testLsns = new ArrayList JavaDoc();
286
287         fillLogFile(numIters, testLsns, testObjs);
288         LastFileReader reader = new LastFileReader(envImpl, 10);
289         checkLogEnd(reader, numIters, testLsns, testObjs);
290     }
291
292     /**
293      * Run with medium buffers.
294      */

295     public void testMedBuffers()
296         throws Throwable JavaDoc {
297
298         initEnv();
299         int numIters = 50;
300         List JavaDoc testObjs = new ArrayList JavaDoc();
301         List JavaDoc testLsns = new ArrayList JavaDoc();
302
303         fillLogFile(numIters, testLsns, testObjs);
304         LastFileReader reader = new LastFileReader(envImpl, 100);
305         checkLogEnd(reader, numIters, testLsns, testObjs);
306     }
307
308     /**
309      * Put junk at the end of the file.
310      */

311     public void testJunk()
312         throws Throwable JavaDoc {
313
314         initEnv();
315         int numIters = 50;
316         List JavaDoc testObjs = new ArrayList JavaDoc();
317         List JavaDoc testLsns = new ArrayList JavaDoc();
318
319         /* Write junk into the end of the file. */
320         fillLogFile(numIters, testLsns, testObjs);
321         long lastFileNum = fileManager.getLastFileNum().longValue();
322         String JavaDoc lastFile =
323             fileManager.getFullFileName(lastFileNum,
324                                         FileManager.JE_SUFFIX);
325
326         RandomAccessFile JavaDoc file =
327             new RandomAccessFile JavaDoc(lastFile, FileManager.FileMode.
328                                  READWRITE_MODE.getModeValue());
329         file.seek(file.length());
330         file.writeBytes("hello, some junk");
331         file.close();
332
333
334         /* Read. */
335         LastFileReader reader = new LastFileReader(envImpl, 100);
336         checkLogEnd(reader, numIters, testLsns, testObjs);
337     }
338
339     /**
340      * Make a log, then make a few extra files at the end, one empty, one with
341      * a bad file header.
342      */

343     public void testExtraEmpty()
344         throws Throwable JavaDoc {
345
346         initEnv();
347         int numIters = 50;
348         List JavaDoc testObjs = new ArrayList JavaDoc();
349         List JavaDoc testLsns = new ArrayList JavaDoc();
350         int defaultBufferSize =
351             configManager.getInt(EnvironmentParams.LOG_ITERATOR_READ_SIZE);
352
353         /*
354          * Make a valid log with data, then put a couple of extra files after
355          * it. Make the file numbers non-consecutive. We should have three log
356          * files.
357          */

358         /* Create a log */
359         fillLogFile(numIters, testLsns, testObjs);
360
361         /* First empty log file -- header, no data. */
362         fileManager.bumpLsn(100000000);
363         fileManager.bumpLsn(100000000);
364         FileManagerTestUtils.createLogFile(fileManager, envImpl, 10);
365
366         /* Second empty log file -- header, no data. */
367         fileManager.bumpLsn(100000000);
368         fileManager.bumpLsn(100000000);
369         FileManagerTestUtils.createLogFile(fileManager, envImpl, 10);
370
371         assertEquals(3, fileManager.getAllFileNumbers().length);
372
373         /*
374          * Corrupt the last empty file and then search for the correct last
375          * file.
376          */

377         long lastFileNum = fileManager.getLastFileNum().longValue();
378         String JavaDoc lastFile =
379             fileManager.getFullFileName(lastFileNum,
380                                         FileManager.JE_SUFFIX);
381         RandomAccessFile JavaDoc file =
382             new RandomAccessFile JavaDoc(lastFile, FileManager.FileMode.
383                                  READWRITE_MODE.getModeValue());
384         file.getChannel().truncate(10);
385         file.close();
386         fileManager.clear();
387
388         /*
389          * Make a reader, read the log. After the reader returns, we should
390          * only have 2 log files.
391          */

392         LastFileReader reader = new LastFileReader(envImpl,
393                                                    defaultBufferSize);
394         checkLogEnd(reader, numIters, testLsns, testObjs);
395         assertEquals(2, fileManager.getAllFileNumbers().length);
396
397         /*
398          * Corrupt the now "last" empty file and try again. This is actually
399          * the first empty file we made.
400          */

401         lastFileNum = fileManager.getLastFileNum().longValue();
402         lastFile = fileManager.getFullFileName(lastFileNum,
403                                                FileManager.JE_SUFFIX);
404         file = new RandomAccessFile JavaDoc(lastFile, FileManager.FileMode.
405                                     READWRITE_MODE.getModeValue());
406         file.getChannel().truncate(10);
407         file.close();
408
409         /*
410          * Validate that we have the right number of log entries, and only one
411          * valid log file.
412          */

413         reader = new LastFileReader(envImpl, defaultBufferSize);
414         checkLogEnd(reader, numIters, testLsns, testObjs);
415         assertEquals(1, fileManager.getAllFileNumbers().length);
416     }
417
418
419     /**
420      * Write a logfile of entries, then read the end.
421      */

422     private void fillLogFile(int numIters, List JavaDoc testLsns, List JavaDoc testObjs)
423         throws Throwable JavaDoc {
424
425         /*
426          * Create a log file full of LNs, INs and Debug Records.
427          */

428         for (int i = 0; i < numIters; i++) {
429             /* Add a debug record. */
430             LoggableObject loggableObj =
431                 new Tracer("Hello there, rec " + (i+1));
432             testObjs.add(loggableObj);
433             testLsns.add(new Long JavaDoc(logManager.log(loggableObj)));
434
435             /* Add an LN. */
436             byte [] data = new byte[i+1];
437             Arrays.fill(data, (byte)(i+1));
438             loggableObj = new LN(data);
439
440             testObjs.add(loggableObj);
441             testLsns.add(new Long JavaDoc(logManager.log(loggableObj)));
442         }
443
444         /* Flush the log, files. */
445     logManager.flush();
446         fileManager.clear();
447     }
448
449     /**
450      * Use the LastFileReader to check this file, see if the log end is set
451      * right.
452      */

453     private void checkLogEnd(LastFileReader reader,
454                  int numIters,
455                              List JavaDoc testLsns,
456                  List JavaDoc testObjs)
457         throws Throwable JavaDoc {
458
459         reader.setTargetType(LogEntryType.LOG_ROOT);
460         reader.setTargetType(LogEntryType.LOG_LN);
461         reader.setTargetType(LogEntryType.LOG_TRACE);
462         reader.setTargetType(LogEntryType.LOG_IN);
463         reader.setTargetType(LogEntryType.LOG_LN_TRANSACTIONAL);
464
465         /* Now ask the LastFileReader to read it back. */
466         while (reader.readNextEntry()) {
467         }
468         
469         /* Truncate the file. */
470         reader.setEndOfFile();
471
472         /*
473      * How many entries did the iterator go over? We should see
474      * numIters * 2 + 7
475      * (the extra 7 are the root, debug records and checkpoints and file
476      * header written by recovery.
477      */

478         assertEquals("should have seen this many entries", (numIters * 2) + 7,
479                      reader.getNumRead());
480
481         /* Check last used LSN. */
482         int numLsns = testLsns.size();
483         long lastLsn = DbLsn.longToLsn((Long JavaDoc) testLsns.get(numLsns - 1));
484         assertEquals("last LSN", lastLsn, reader.getLastLsn());
485
486         /* Check last offset. */
487         assertEquals("prev offset", DbLsn.getFileOffset(lastLsn),
488                      reader.getPrevOffset());
489
490         /* Check next available LSN. */
491         int lastSize =
492             ((LogWritable)testObjs.get(testObjs.size()-1)).getLogSize();
493         assertEquals("next available",
494                      DbLsn.makeLsn(DbLsn.getFileNumber(lastLsn),
495                    DbLsn.getFileOffset(lastLsn) +
496                    LogManager.HEADER_BYTES + lastSize),
497                      reader.getEndOfLog());
498
499         /* The log should be truncated to just the right size. */
500         FileHandle handle = fileManager.getFileHandle(0L);
501         RandomAccessFile JavaDoc file = handle.getFile();
502         assertEquals(DbLsn.getFileOffset(reader.getEndOfLog()),
503                      file.getChannel().size());
504         handle.release();
505         fileManager.clear();
506
507         /* Check the last tracked LSNs. */
508         assertTrue(reader.getLastSeen(LogEntryType.LOG_ROOT) !=
509            DbLsn.NULL_LSN);
510         assertTrue(reader.getLastSeen(LogEntryType.LOG_IN) == DbLsn.NULL_LSN);
511         assertTrue(reader.getLastSeen(LogEntryType.LOG_LN_TRANSACTIONAL) ==
512            DbLsn.NULL_LSN);
513         assertEquals(reader.getLastSeen(LogEntryType.LOG_TRACE),
514                      DbLsn.longToLsn((Long JavaDoc) testLsns.get(numLsns-2)));
515         assertEquals(reader.getLastSeen(LogEntryType.LOG_LN),
516                      lastLsn);
517     }
518 }
519
Popular Tags