001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: DbRunAction.java,v 1.31.2.4 2008/01/07 15:14:17 cwl Exp $
007: */
008:
009: package com.sleepycat.je.util;
010:
011: import java.io.BufferedReader;
012: import java.io.File;
013: import java.io.IOException;
014: import java.io.InputStreamReader;
015: import java.text.DecimalFormat;
016:
017: import com.sleepycat.je.CheckpointConfig;
018: import com.sleepycat.je.Cursor;
019: import com.sleepycat.je.Database;
020: import com.sleepycat.je.DatabaseEntry;
021: import com.sleepycat.je.DatabaseException;
022: import com.sleepycat.je.DbInternal;
023: import com.sleepycat.je.Environment;
024: import com.sleepycat.je.EnvironmentConfig;
025: import com.sleepycat.je.EnvironmentMutableConfig;
026: import com.sleepycat.je.EnvironmentStats;
027: import com.sleepycat.je.LockMode;
028: import com.sleepycat.je.OperationStatus;
029: import com.sleepycat.je.StatsConfig;
030: import com.sleepycat.je.Transaction;
031: import com.sleepycat.je.config.EnvironmentParams;
032: import com.sleepycat.je.dbi.EnvironmentImpl;
033: import com.sleepycat.je.utilint.CmdUtil;
034:
035: /**
036: * DbRunAction is a debugging aid that can invoke a JE operation or
037: * background activity from the command line.
038: *
039: * batchClean calls Environment.cleanLog() in a loop
040: * checkpoint calls Environment.checkpoint() with force=true
041: * compress calls Environment.compress
042: * evict calls Environment.preload, then evictMemory
043: * removeDb calls Environment.removeDatabase, but doesn't do any cleaning
044: * removeDbAndClean calls removeDatabase, then cleanLog in a loop
045: * activateCleaner wakes up the cleaner, and then the main thread waits
046: * until you type "y" to the console before calling Environment.close().
047: * The control provided by the prompt is necessary for daemon activities
048: * because often threads check and bail out if the environment is closed.
049: */
050: public class DbRunAction {
051:
052: private static final int NONE = 0;
053: private static final int BATCH_CLEAN = 1; // app-driven batch cleaning
054: private static final int COMPRESS = 2;
055: private static final int EVICT = 3;
056: private static final int CHECKPOINT = 4;
057: private static final int REMOVEDB = 5;
058: private static final int REMOVEDB_AND_CLEAN = 6;
059: private static final int ACTIVATE_CLEANER_THREADS = 7;
060:
061: // wake up cleaner threads
062:
063: public static void main(String[] argv) {
064:
065: long recoveryStart = 0;
066: long actionStart = 0;
067: long actionEnd = 0;
068:
069: try {
070: int whichArg = 0;
071: if (argv.length == 0) {
072: usage();
073: System.exit(1);
074: }
075:
076: String dbName = null;
077: int doAction = 0;
078: String envHome = ".";
079: boolean readOnly = false;
080: boolean printStats = false;
081:
082: while (whichArg < argv.length) {
083: String nextArg = argv[whichArg];
084:
085: if (nextArg.equals("-h")) {
086: whichArg++;
087: envHome = CmdUtil.getArg(argv, whichArg);
088: } else if (nextArg.equals("-a")) {
089: whichArg++;
090: String action = CmdUtil.getArg(argv, whichArg);
091: if (action.equalsIgnoreCase("batchClean")) {
092: doAction = BATCH_CLEAN;
093: } else if (action.equalsIgnoreCase("compress")) {
094: doAction = COMPRESS;
095: } else if (action.equalsIgnoreCase("checkpoint")) {
096: doAction = CHECKPOINT;
097: } else if (action.equalsIgnoreCase("evict")) {
098: doAction = EVICT;
099: } else if (action.equalsIgnoreCase("removedb")) {
100: doAction = REMOVEDB;
101: } else if (action
102: .equalsIgnoreCase("removedbAndClean")) {
103: doAction = REMOVEDB_AND_CLEAN;
104: } else if (action
105: .equalsIgnoreCase("activateCleaner")) {
106: doAction = ACTIVATE_CLEANER_THREADS;
107: } else {
108: usage();
109: System.exit(1);
110: }
111: } else if (nextArg.equals("-ro")) {
112: readOnly = true;
113: } else if (nextArg.equals("-s")) {
114: dbName = argv[++whichArg];
115: } else if (nextArg.equals("-stats")) {
116: printStats = true;
117: } else {
118: throw new IllegalArgumentException(nextArg
119: + " is not a supported option.");
120: }
121: whichArg++;
122: }
123:
124: /* Make an environment */
125: EnvironmentConfig envConfig = new EnvironmentConfig();
126:
127: /* Do debug log to the console.*/
128: envConfig.setConfigParam(
129: EnvironmentParams.JE_LOGGING_CONSOLE.getName(),
130: "true");
131:
132: /* Don't debug log to the database log. */
133: if (readOnly) {
134: envConfig.setConfigParam(
135: EnvironmentParams.JE_LOGGING_DBLOG.getName(),
136: "false");
137:
138: envConfig.setReadOnly(true);
139: }
140:
141: /*
142: * If evicting, scan the given database first and don't run the
143: * background evictor.
144: */
145: if (doAction == EVICT) {
146:
147: envConfig.setConfigParam(
148: EnvironmentParams.ENV_RUN_EVICTOR.getName(),
149: "false");
150: envConfig.setConfigParam(
151: EnvironmentParams.EVICTOR_CRITICAL_PERCENTAGE
152: .getName(), "1000");
153: }
154:
155: recoveryStart = System.currentTimeMillis();
156:
157: Environment env = new Environment(new File(envHome),
158: envConfig);
159:
160: CheckpointConfig forceConfig = new CheckpointConfig();
161: forceConfig.setForce(true);
162:
163: Thread statsPrinter = null;
164: if (printStats) {
165: statsPrinter = new StatsPrinter(env);
166: statsPrinter.start();
167: }
168:
169: boolean promptForShutdown = false;
170: actionStart = System.currentTimeMillis();
171: switch (doAction) {
172: case BATCH_CLEAN:
173: /* Since this is batch cleaning, repeat until no progress. */
174: while (true) {
175: int nFiles = env.cleanLog();
176: System.out.println("Files cleaned: " + nFiles);
177: if (nFiles == 0) {
178: break;
179: }
180: }
181: env.checkpoint(forceConfig);
182: break;
183: case COMPRESS:
184: env.compress();
185: break;
186: case CHECKPOINT:
187: env.checkpoint(forceConfig);
188: break;
189: case EVICT:
190: preload(env, dbName);
191: break;
192: case REMOVEDB:
193: removeAndClean(env, dbName, false);
194: break;
195: case REMOVEDB_AND_CLEAN:
196: removeAndClean(env, dbName, true);
197: break;
198: case ACTIVATE_CLEANER_THREADS:
199: EnvironmentImpl envImpl = DbInternal
200: .envGetEnvironmentImpl(env);
201: envImpl.getCleaner().wakeup();
202: promptForShutdown = true;
203: break;
204: }
205: actionEnd = System.currentTimeMillis();
206:
207: if (promptForShutdown) {
208: /*
209: * If the requested action is a daemon driven one, we
210: * don't want the main thread to shutdown the environment
211: * until we say we're ready
212: */
213: waitForShutdown();
214: }
215: if (statsPrinter != null) {
216: statsPrinter.interrupt();
217: statsPrinter.join();
218: }
219: env.close();
220: } catch (Exception e) {
221: e.printStackTrace();
222: System.out.println(e.getMessage());
223: usage();
224: System.exit(1);
225: } finally {
226: DecimalFormat f = new DecimalFormat();
227: f.setMaximumFractionDigits(2);
228:
229: long recoveryDuration = actionStart - recoveryStart;
230: System.out.println("\nrecovery time = "
231: + f.format(recoveryDuration) + " millis "
232: + f.format((double) recoveryDuration / 60000)
233: + " minutes");
234:
235: long actionDuration = actionEnd - actionStart;
236: System.out.println("action time = "
237: + f.format(actionDuration) + " millis "
238: + f.format(actionDuration / 60000) + " minutes");
239:
240: }
241: }
242:
243: private static void removeAndClean(Environment env, String name,
244: boolean doCleaning) throws DatabaseException {
245:
246: long a, b, c, d, e, f;
247:
248: // Transaction txn = env.beginTransaction(null, null);
249: Transaction txn = null;
250: CheckpointConfig force = new CheckpointConfig();
251: force.setForce(true);
252:
253: a = System.currentTimeMillis();
254: env.removeDatabase(txn, name);
255: b = System.currentTimeMillis();
256: // txn.commit();
257: c = System.currentTimeMillis();
258:
259: int cleanedCount = 0;
260: if (doCleaning) {
261: while (env.cleanLog() > 0) {
262: cleanedCount++;
263: }
264: }
265: d = System.currentTimeMillis();
266:
267: System.out.println("cleanedCount=" + cleanedCount);
268: e = 0;
269: f = 0;
270: if (cleanedCount > 0) {
271: e = System.currentTimeMillis();
272: env.checkpoint(force);
273: f = System.currentTimeMillis();
274: }
275:
276: System.out.println("Remove of " + name + " remove: "
277: + getSecs(a, b) + " commit: " + getSecs(b, c)
278: + " clean: " + getSecs(c, d) + " checkpoint: "
279: + getSecs(e, f));
280: }
281:
282: private static String getSecs(long start, long end) {
283: return (end - start) / 1000 + " secs";
284: }
285:
286: private static void preload(Environment env, String dbName)
287: throws DatabaseException {
288:
289: System.out.println("Preload starting");
290: Database db = env.openDatabase(null, dbName, null);
291: Cursor cursor = db.openCursor(null, null);
292: try {
293: DatabaseEntry key = new DatabaseEntry();
294: DatabaseEntry data = new DatabaseEntry();
295: int count = 0;
296: while (cursor.getNext(key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
297: count++;
298: if ((count % 50000) == 0) {
299: System.out.println(count + "...");
300: }
301: }
302: System.out.println("Preloaded " + count + " records");
303: } finally {
304: cursor.close();
305: db.close();
306: }
307: }
308:
309: private static void doEvict(Environment env)
310: throws DatabaseException {
311:
312: /* push the cache size down by half to force eviction. */
313: EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
314: long cacheUsage = envImpl.getMemoryBudget()
315: .getCacheMemoryUsage();
316: EnvironmentMutableConfig c = new EnvironmentMutableConfig();
317: c.setCacheSize(cacheUsage / 2);
318: env.setMutableConfig(c);
319:
320: long start = System.currentTimeMillis();
321: env.evictMemory();
322: long end = System.currentTimeMillis();
323:
324: DecimalFormat f = new DecimalFormat();
325: f.setMaximumFractionDigits(2);
326: System.out.println("evict time=" + f.format(end - start));
327: }
328:
329: private static void waitForShutdown() throws IOException {
330:
331: System.out
332: .println("Wait for daemon activity to run. When ready to stop, type (y)");
333: BufferedReader reader = new BufferedReader(
334: new InputStreamReader(System.in));
335: do {
336: String val = reader.readLine();
337: if (val != null
338: && (val.equalsIgnoreCase("y") || val
339: .equalsIgnoreCase("yes"))) {
340: break;
341: } else {
342: System.out.println("Shutdown? (y)");
343: }
344: } while (true);
345: }
346:
347: private static class StatsPrinter extends Thread {
348:
349: private Environment env;
350:
351: StatsPrinter(Environment env) {
352: this .env = env;
353: }
354:
355: public void run() {
356:
357: StatsConfig clearConfig = new StatsConfig();
358: clearConfig.setClear(true);
359:
360: while (true) {
361: try {
362: synchronized (this ) {
363: wait(30 * 1000);
364: }
365: EnvironmentStats stats = env.getStats(clearConfig);
366: System.out.println("\n" + stats + "\n");
367: } catch (DatabaseException e) {
368: e.printStackTrace();
369: break;
370: } catch (InterruptedException e) {
371: break;
372: }
373: }
374: }
375: }
376:
377: private static void usage() {
378: System.out.println("Usage: \n "
379: + CmdUtil.getJavaCommand(DbRunAction.class));
380: System.out.println(" -h <environment home> ");
381: System.out
382: .println(" -a <batchClean|compress|evict|checkpoint|"
383: + "removeDb|removeDbAndClean|activateCleaner>");
384: System.out
385: .println(" -ro (read-only - defaults to read-write)");
386: System.out.println(" -s <dbName> (for removeDb)");
387: System.out.println(" -stats (print every 30 seconds)");
388: }
389: }
|