KickJava   Java API By Example, From Geeks To Geeks.

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


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

8
9 package com.sleepycat.je.log;
10
11 import java.io.IOException JavaDoc;
12 import java.nio.ByteBuffer JavaDoc;
13 import java.util.HashSet JavaDoc;
14 import java.util.Set JavaDoc;
15
16 import com.sleepycat.je.DatabaseException;
17 import com.sleepycat.je.dbi.EnvironmentImpl;
18 import com.sleepycat.je.log.entry.LogEntry;
19 import com.sleepycat.je.utilint.DbLsn;
20
21 /**
22  * A ScavengerFileReader reads the log backwards. If it encounters a checksum
23  * error, it goes to the start of that log file and reads forward until it
24  * encounters a checksum error. It then continues the reading backwards in the
25  * log.
26  *
27  * The caller may set "dumpCorruptedBounds" to true if information about the
28  * start and finish of the corrupted portion should be displayed on stderr.
29  *
30  * The caller is expected to implement processEntryCallback. This method is
31  * called once for each entry that the ScavengerFileReader finds in the log.
32  */

33 abstract public class ScavengerFileReader extends FileReader {
34
35     /* A Set of the entry type numbers that this FileReader should dump. */
36     private Set JavaDoc targetEntryTypes;
37
38     private int readBufferSize;
39
40     /* True if reader should write corrupted boundaries to System.err. */
41     private boolean dumpCorruptedBounds;
42
43     /**
44      * Create this reader to start at a given LSN.
45      */

46     public ScavengerFileReader(EnvironmentImpl env,
47                    int readBufferSize,
48                    long startLsn,
49                    long finishLsn,
50                    long endOfFileLsn)
51     throws IOException JavaDoc, DatabaseException {
52
53         super(env,
54               readBufferSize,
55           false,
56               startLsn,
57           null, // single file number
58
endOfFileLsn,
59           finishLsn);
60
61     this.readBufferSize = readBufferSize;
62
63     /*
64      * Indicate that a checksum error should not shutdown the whole
65      * environment.
66      */

67     anticipateChecksumErrors = true;
68         targetEntryTypes = new HashSet JavaDoc();
69     dumpCorruptedBounds = false;
70     }
71
72     /**
73      * Set to true if corrupted boundaries should be dumped to stderr.
74      */

75     public void setDumpCorruptedBounds(boolean dumpCorruptedBounds) {
76     this.dumpCorruptedBounds = dumpCorruptedBounds;
77     }
78
79     /**
80      * Tell the reader that we are interested in these kind of entries.
81      */

82     public void setTargetType(LogEntryType type) {
83         targetEntryTypes.add(new Byte JavaDoc(type.getTypeNum()));
84     }
85
86     /*
87      * For each entry that is selected, just call processEntryCallback.
88      */

89     protected boolean processEntry(ByteBuffer JavaDoc entryBuffer)
90         throws DatabaseException {
91
92         LogEntryType lastEntryType =
93             LogEntryType.findType(currentEntryTypeNum,
94                   currentEntryTypeVersion);
95     LogEntry entry = lastEntryType.getSharedLogEntry();
96         entry.readEntry(entryBuffer, currentEntrySize,
97                         currentEntryTypeVersion, true);
98     processEntryCallback(entry, lastEntryType);
99         return true;
100     }
101
102     /*
103      * Method overriden by the caller. Each entry of the types selected
104      * is passed to this method.
105      */

106     abstract protected void processEntryCallback(LogEntry entry,
107                          LogEntryType entryType)
108     throws DatabaseException;
109
110     /*
111      * Read the next entry. If a checksum exception is encountered, attempt
112      * to find the other side of the corrupted area and try to re-read this
113      * file.
114      */

115     public boolean readNextEntry()
116         throws DatabaseException, IOException JavaDoc {
117
118     long saveCurrentEntryOffset = currentEntryOffset;
119     try {
120         return super.readNextEntry();
121     } catch (DbChecksumException DCE) {
122         resyncReader(DbLsn.makeLsn(readBufferFileNum,
123                        saveCurrentEntryOffset),
124              dumpCorruptedBounds);
125         return super.readNextEntry();
126     }
127     }
128
129     /*
130      * A checksum error has been encountered. Go to the start of this log file
131      * and read forward until the lower side of the corrupted area has been
132      * found.
133      */

134     protected boolean resyncReader(long nextGoodRecordPostCorruption,
135                    boolean showCorruptedBounds)
136     throws DatabaseException, IOException JavaDoc {
137
138         LastFileReader reader = null;
139     long tryReadBufferFileNum =
140         DbLsn.getFileNumber(nextGoodRecordPostCorruption);
141
142     while (tryReadBufferFileNum >= 0) {
143         try {
144         reader = new LastFileReader(env,
145                         readBufferSize,
146                         new Long JavaDoc(tryReadBufferFileNum));
147         break;
148         } catch (DbChecksumException DCE) {
149
150         /*
151          * We found a checksum error reading the header of this file
152          * so skip to a completely earlier file.
153          */

154         tryReadBufferFileNum--;
155         continue;
156         }
157     }
158
159     boolean switchedFiles = tryReadBufferFileNum !=
160         DbLsn.getFileNumber(nextGoodRecordPostCorruption);
161
162     if (!switchedFiles) {
163
164         /*
165          * This reader will not throw an exception if a checksum error is
166          * hit -- it will just exit.
167          */

168         while (reader.readNextEntry()) {
169         }
170     }
171
172         long lastUsedLsn = reader.getLastValidLsn();
173     long nextAvailableLsn = reader.getEndOfLog();
174     if (showCorruptedBounds) {
175         System.err.println("A checksum error was found in the log.");
176         System.err.println
177         ("Corruption begins at LSN:\n " +
178          DbLsn.toString(nextAvailableLsn));
179         System.err.println
180         ("Last known good record before corruption is at LSN:\n " +
181          DbLsn.toString(lastUsedLsn));
182         System.err.println
183         ("Next known good record after corruption is at LSN:\n " +
184          DbLsn.toString(nextGoodRecordPostCorruption));
185     }
186
187         startLsn = lastUsedLsn;
188     initStartingPosition(nextAvailableLsn, null);
189     if (switchedFiles) {
190         currentEntryPrevOffset = 0;
191     }
192     /* Indicate resync is permitted so don't throw exception. */
193     return true;
194     }
195
196     /**
197      * @return true if this reader should process this entry, or just skip
198      * over it.
199      */

200     protected boolean isTargetEntry(byte logEntryTypeNumber,
201                                     byte logEntryTypeVersion) {
202     if (targetEntryTypes.size() == 0) {
203         /* We want to dump all entry types. */
204         return true;
205     } else {
206         return targetEntryTypes.contains(new Byte JavaDoc(logEntryTypeNumber));
207     }
208     }
209 }
210
Popular Tags