001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: DbVerify.java,v 1.42.2.4 2008/01/07 15:14:17 cwl Exp $
007: */
008:
009: package com.sleepycat.je.util;
010:
011: import java.io.File;
012: import java.io.PrintStream;
013: import java.util.ArrayList;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.logging.Level;
017:
018: import com.sleepycat.je.Database;
019: import com.sleepycat.je.DatabaseConfig;
020: import com.sleepycat.je.DatabaseException;
021: import com.sleepycat.je.DatabaseStats;
022: import com.sleepycat.je.DbInternal;
023: import com.sleepycat.je.Environment;
024: import com.sleepycat.je.EnvironmentConfig;
025: import com.sleepycat.je.JEVersion;
026: import com.sleepycat.je.VerifyConfig;
027: import com.sleepycat.je.cleaner.VerifyUtils;
028: import com.sleepycat.je.dbi.DatabaseImpl;
029: import com.sleepycat.je.dbi.DbTree;
030: import com.sleepycat.je.dbi.EnvironmentImpl;
031: import com.sleepycat.je.utilint.CmdUtil;
032: import com.sleepycat.je.utilint.Tracer;
033:
034: public class DbVerify {
035: private static final String usageString = "usage: "
036: + CmdUtil.getJavaCommand(DbVerify.class)
037: + "\n"
038: + " -h <dir> # environment home directory\n"
039: + " [-c ] # check cleaner metadata\n"
040: + " [-q ] # quiet, exit with success or failure\n"
041: + " [-s <databaseName> ] # database to verify\n"
042: + " [-v <interval>] # progress notification interval\n"
043: + " [-V] # print JE version number";
044:
045: protected File envHome = null;
046: protected Environment env;
047: protected String dbName = null;
048: protected boolean quiet = false;
049: protected boolean checkLsns = false;
050: protected boolean openReadOnly = true;
051: private boolean doClose;
052:
053: private int progressInterval = 0;
054:
055: static public void main(String argv[]) throws DatabaseException {
056:
057: DbVerify verifier = new DbVerify();
058: verifier.parseArgs(argv);
059:
060: boolean ret = false;
061: try {
062: ret = verifier.verify(System.err);
063: } catch (Throwable T) {
064: if (!verifier.quiet) {
065: T.printStackTrace(System.err);
066: }
067: } finally {
068:
069: verifier.closeEnv();
070:
071: /*
072: * Show the status, only omit if the user asked for a quiet
073: * run and didn't specify a progress interval, in which case
074: * we can assume that they really don't want any status output.
075: *
076: * If the user runs this from the command line, presumably they'd
077: * like to see the status.
078: */
079: if ((!verifier.quiet) || (verifier.progressInterval > 0)) {
080: System.err.println("Exit status = " + ret);
081: }
082:
083: System.exit(ret ? 0 : -1);
084: }
085: }
086:
087: DbVerify() {
088: doClose = true;
089: }
090:
091: public DbVerify(Environment env, String dbName, boolean quiet) {
092: this .env = env;
093: this .dbName = dbName;
094: this .quiet = quiet;
095: doClose = false;
096: }
097:
098: protected void printUsage(String msg) {
099: System.err.println(msg);
100: System.err.println(usageString);
101: System.exit(-1);
102: }
103:
104: protected void parseArgs(String argv[]) {
105:
106: int argc = 0;
107: int nArgs = argv.length;
108: while (argc < nArgs) {
109: String this Arg = argv[argc++];
110: if (this Arg.equals("-q")) {
111: quiet = true;
112: } else if (this Arg.equals("-V")) {
113: System.out.println(JEVersion.CURRENT_VERSION);
114: System.exit(0);
115: } else if (this Arg.equals("-h")) {
116: if (argc < nArgs) {
117: envHome = new File(argv[argc++]);
118: } else {
119: printUsage("-h requires an argument");
120: }
121: } else if (this Arg.equals("-s")) {
122: if (argc < nArgs) {
123: dbName = argv[argc++];
124: } else {
125: printUsage("-s requires an argument");
126: }
127: } else if (this Arg.equals("-v")) {
128: if (argc < nArgs) {
129: progressInterval = Integer.parseInt(argv[argc++]);
130: if (progressInterval <= 0) {
131: printUsage("-v requires a positive argument");
132: }
133: } else {
134: printUsage("-v requires an argument");
135: }
136: } else if (this Arg.equals("-c")) {
137: checkLsns = true;
138: } else if (this Arg.equals("-rw")) {
139:
140: /*
141: * Unadvertised option. Open the environment read/write
142: * so that a checkLsns pass gets an accurate root LSN to
143: * start from in the event that a recovery split the root.
144: * A read/only environment open will keep any logging in
145: * the log buffers, and the LSNs stored in the INs will
146: * be converted to DbLsn.NULL_LSN.
147: */
148: openReadOnly = false;
149: }
150: }
151:
152: if (envHome == null) {
153: printUsage("-h is a required argument");
154: }
155: }
156:
157: protected void openEnv() throws DatabaseException {
158:
159: if (env == null) {
160: EnvironmentConfig envConfig = new EnvironmentConfig();
161: envConfig.setReadOnly(openReadOnly);
162: env = new Environment(envHome, envConfig);
163: }
164: }
165:
166: void closeEnv() throws DatabaseException {
167:
168: try {
169: if (env != null) {
170: env.close();
171: }
172: } finally {
173: env = null;
174: }
175: }
176:
177: public boolean verify(PrintStream out) throws DatabaseException {
178:
179: boolean ret = true;
180: try {
181: VerifyConfig verifyConfig = new VerifyConfig();
182: verifyConfig.setPrintInfo(!quiet);
183: if (progressInterval > 0) {
184: verifyConfig.setShowProgressInterval(progressInterval);
185: verifyConfig.setShowProgressStream(out);
186: }
187:
188: openEnv();
189: EnvironmentImpl envImpl = DbInternal
190: .envGetEnvironmentImpl(env);
191:
192: /* If no database is specified, verify all. */
193: List dbNameList = null;
194: List internalDbs = null;
195: DbTree dbMapTree = envImpl.getDbMapTree();
196:
197: if (dbName == null) {
198: dbNameList = env.getDatabaseNames();
199:
200: dbNameList.addAll(dbMapTree.getInternalDbNames());
201: internalDbs = dbMapTree.getInternalNoLookupDbNames();
202: } else {
203: dbNameList = new ArrayList();
204: dbNameList.add(dbName);
205: internalDbs = new ArrayList();
206: }
207:
208: /* Check application data. */
209: Iterator iter = dbNameList.iterator();
210: while (iter.hasNext()) {
211: String targetDb = (String) iter.next();
212: Tracer.trace(Level.INFO, envImpl, "DbVerify.verify of "
213: + targetDb + " starting");
214:
215: DatabaseConfig dbConfig = new DatabaseConfig();
216: dbConfig.setReadOnly(true);
217: dbConfig.setAllowCreate(false);
218: DbInternal.setUseExistingConfig(dbConfig, true);
219: Database db = env
220: .openDatabase(null, targetDb, dbConfig);
221:
222: try {
223: if (!verifyOneDbImpl(DbInternal
224: .dbGetDatabaseImpl(db), targetDb,
225: verifyConfig, out)) {
226: ret = false;
227: }
228: } finally {
229: if (db != null) {
230: db.close();
231: }
232: Tracer.trace(Level.INFO, envImpl,
233: "DbVerify.verify of " + targetDb
234: + " ending");
235: }
236: }
237:
238: /*
239: * Check internal databases, which don't have to be opened
240: * through a Database handle.
241: */
242: iter = internalDbs.iterator();
243: while (iter.hasNext()) {
244: String targetDb = (String) iter.next();
245: Tracer.trace(Level.INFO, envImpl, "DbVerify.verify of "
246: + targetDb + " starting");
247:
248: try {
249: DatabaseImpl dbImpl = dbMapTree.getDb(null,
250: targetDb, null);
251: try {
252: if (!verifyOneDbImpl(dbImpl, targetDb,
253: verifyConfig, out)) {
254: ret = false;
255: }
256: } finally {
257: dbMapTree.releaseDb(dbImpl);
258: }
259: } finally {
260: Tracer.trace(Level.INFO, envImpl,
261: "DbVerify.verify of " + targetDb
262: + " ending");
263: }
264: }
265:
266: if (doClose) {
267: closeEnv();
268: }
269: } catch (DatabaseException DE) {
270: ret = false;
271: try {
272: closeEnv();
273: } catch (Throwable ignored) {
274:
275: /*
276: * Klockwork - ok
277: * Don't say anything about exceptions here.
278: */
279: }
280: throw DE;
281: }
282:
283: return ret;
284: }
285:
286: private boolean verifyOneDbImpl(DatabaseImpl dbImpl, String name,
287: VerifyConfig verifyConfig, PrintStream out)
288: throws DatabaseException {
289: boolean status = true;
290:
291: if (verifyConfig.getPrintInfo()) {
292: out.println("Verifying database " + name);
293: }
294:
295: /*
296: * First check the tree. Use DatabaseImpl.verify so we can get a status
297: * return.
298: */
299: if (verifyConfig.getPrintInfo()) {
300: out.println("Checking tree for " + name);
301: }
302: DatabaseStats stats = dbImpl.getEmptyStats();
303: status = dbImpl.verify(verifyConfig, stats);
304: if (verifyConfig.getPrintInfo()) {
305: /*
306: * Intentionally use print, not println, because stats.toString()
307: * puts in a newline too.
308: */
309: out.print(stats);
310: }
311:
312: /* Then check the obsolete lsns */
313: if (verifyConfig.getPrintInfo()) {
314: out.println("Checking obsolete offsets for " + name);
315: }
316: try {
317: VerifyUtils.checkLsns(dbImpl, out);
318: } catch (DatabaseException e) {
319: if (verifyConfig.getPrintInfo()) {
320: out.println("Problem from checkLsns:" + e);
321: }
322: status = false;
323: }
324: if (verifyConfig.getPrintInfo()) {
325: out.println();
326: }
327: return status;
328: }
329: }
|