/* * Clear as many resources as possible, even in the face of an environment * that has received a fatal error, in order to support reopening the * environment in the same JVM. */ public synchronized void closeAfterRunRecovery() throws DatabaseException { try { shutdownDaemons(); } catch (InterruptedException IE) { /* Klockwork - ok */ } try { fileManager.clear(); } catch (Exception e) { /* Klockwork - ok */ } try { fileManager.close(); } catch (Exception e) { /* Klockwork - ok */ } DbEnvPool.getInstance().remove(envHome); }
private void doClose(boolean doCheckpoint) throws DatabaseException { StringBuffer errors = new StringBuffer(); try { // refined trace Tracer.trace(Level.FINE, this, "Close of // environment " + envHome + " started"); try { envState.checkState(DbEnvState.VALID_FOR_CLOSE, DbEnvState.CLOSED); } catch (DatabaseException DBE) { throw DBE; } /* * Begin shutdown of the deamons before checkpointing. Cleaning * during the checkpoint is wasted and slows down the checkpoint. */ requestShutdownDaemons(); /* Checkpoint to bound recovery time. */ if (doCheckpoint && !isReadOnly && (envState != DbEnvState.INVALID) && logManager.getLastLsnAtRecovery() != fileManager.getLastUsedLsn()) { /* * Force a checkpoint. Don't allow deltas (minimize recovery * time) because they cause inefficiencies for two reasons: (1) * recovering BINDeltas causes extra random I/O in order to * reconstitute BINS, which can greatly increase recovery time, * and (2) logging deltas during close causes redundant logging * by the full checkpoint after recovery. */ CheckpointConfig ckptConfig = new CheckpointConfig(); ckptConfig.setForce(true); ckptConfig.setMinimizeRecoveryTime(true); try { invokeCheckpoint( ckptConfig, false, // flushAll "close"); } catch (DatabaseException IE) { errors.append("\nException performing checkpoint: "); errors.append(IE.toString()).append("\n"); } } try { shutdownDaemons(); } catch (InterruptedException IE) { errors.append("\nException shutting down daemon threads: "); errors.append(IE.toString()).append("\n"); } /* Flush log. */ // refined trace Tracer.trace(Level.FINE, this, "Env " + envHome + " // daemons shutdown"); try { logManager.flush(); } catch (DatabaseException DBE) { errors.append("\nException flushing log manager: "); errors.append(DBE.toString()).append("\n"); } try { fileManager.clear(); } catch (IOException IOE) { errors.append("\nException clearing file manager: "); errors.append(IOE.toString()).append("\n"); } catch (DatabaseException DBE) { errors.append("\nException clearing file manager: "); errors.append(DBE.toString()).append("\n"); } try { fileManager.close(); } catch (IOException IOE) { errors.append("\nException clearing file manager: "); errors.append(IOE.toString()).append("\n"); } catch (DatabaseException DBE) { errors.append("\nException clearing file manager: "); errors.append(DBE.toString()).append("\n"); } try { inMemoryINs.clear(); } catch (DatabaseException DBE) { errors.append("\nException closing file manager: "); errors.append(DBE.toString()).append("\n"); } hook_afterDoClose(errors); } finally { envState = DbEnvState.CLOSED; } if (errors.length() > 0 && savedInvalidatingException == null) { /* Don't whine again if we've already whined. */ throw new RunRecoveryException(this, errors.toString()); } }
/** * Create a database environment to represent the data in envHome. dbHome. Properties from the * je.properties file in that directory are used to initialize the system wide property bag. * Properties passed to this method are used to influence the open itself. * * @param envHome absolute path of the database environment home directory * @param envConfig * @throws DatabaseException on all other failures */ public EnvironmentImpl(File envHome, EnvironmentConfig envConfig) throws DatabaseException { try { this.envHome = envHome; envState = DbEnvState.INIT; /* Set up configuration parameters */ configManager = new DbConfigManager(envConfig); configObservers = new ArrayList(); addConfigObserver(this); /* * Decide on memory budgets based on environment config params and * memory available to this process. */ memoryBudget = new LogBufferBudget(this, configManager); /* * Set up debug logging. Depending on configuration, add handlers, * set logging level. */ // envLogger = initLogger(envHome); /* * Essential services. These must exist before recovery. */ hook_readProperties(configManager); forcedYield = configManager.getBoolean(EnvironmentParams.ENV_FORCED_YIELD); isNoLocking = !(configManager.getBoolean(EnvironmentParams.ENV_INIT_LOCKING)); isReadOnly = configManager.getBoolean(EnvironmentParams.ENV_RDONLY); fileManager = new FileManager(this, envHome, isReadOnly); if (!envConfig.getAllowCreate() && !fileManager.filesExist()) { throw new DatabaseException( "Enviroment creation isn't allowed, " + " but there is no pre-existing " + " environment in " + envHome); } logManager = new SyncedLogManager(this, isReadOnly); inMemoryINs = new INList(this); txnManager = new TxnManager(this); /* * Make sure that either log-size-based or time-based checkpointing is * enabled. */ checkpointer = new Checkpointer(this); cleaner = new Cleaner(this, "Cleaner"); /* * Daemons are always made here, but only started after recovery. We * want them to exist so we can call them programatically even if * the daemon thread is not started. */ createDaemons(); /* * Recovery will recreate the dbMapTree from the log if it exists. */ dbMapTree = new DbTree(this); referenceCount = 0; /* * Do not do recovery and start daemons if this environment is for a * utility. */ if (configManager.getBoolean(EnvironmentParams.ENV_RECOVERY)) { /* * Run recovery. Note that debug logging to the database log is * disabled until recovery is finished. */ try { RecoveryManager recoveryManager = new RecoveryManager(this); lastRecoveryInfo = recoveryManager.recover(isReadOnly); } finally { try { /* Flush to get all exception tracing out to the log. */ logManager.flush(); fileManager.clear(); } catch (IOException e) { throw new DatabaseException(e.getMessage()); } } } else { isReadOnly = true; noComparators = true; } /* Start daemons after recovery. */ runOrPauseDaemons(configManager); /* * Cache a few critical values. We keep our timeout in millis * instead of microseconds because Object.wait takes millis. */ lockTimeout = PropUtil.microsToMillis(configManager.getLong(EnvironmentParams.LOCK_TIMEOUT)); txnTimeout = PropUtil.microsToMillis(configManager.getLong(EnvironmentParams.TXN_TIMEOUT)); /* Mark as open. */ open(); } catch (DatabaseException e) { /* Release any environment locks if there was a problem. */ if (fileManager != null) { try { fileManager.close(); } catch (IOException IOE) { /* * Klockwork - ok Eat it, we want to throw the original * exception. */ } } throw e; } }