/** * 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; } }
/** Initialize at construction time and when the cache is resized. */ private void reset(DbConfigManager configManager) throws DatabaseException { /* * Calculate the total memory allotted to JE. * 1. If je.maxMemory is specified, use that. Check that it's * not more than the jvm memory. * 2. Otherwise, take je.maxMemoryPercent * JVM max memory. */ long newMaxMemory = configManager.getLong(EnvironmentParams.MAX_MEMORY); long jvmMemory = getRuntimeMaxMemory(); if (newMaxMemory != 0) { /* Application specified a cache size number, validate it. */ if (jvmMemory < newMaxMemory) { throw new IllegalArgumentException( EnvironmentParams.MAX_MEMORY.getName() + " has a value of " + newMaxMemory + " but the JVM is only configured for " + jvmMemory + ". Consider using je.maxMemoryPercent."); } if (newMaxMemory < MIN_MAX_MEMORY_SIZE) { throw new IllegalArgumentException( EnvironmentParams.MAX_MEMORY.getName() + " is " + newMaxMemory + " which is less than the minimum: " + MIN_MAX_MEMORY_SIZE); } } else { /* * When no explicit cache size is specified and the JVM memory size * is unknown, assume a default sized (64 MB) heap. This produces * a reasonable cache size when no heap size is known. */ if (jvmMemory == Long.MAX_VALUE) { jvmMemory = N_64MB; } /* Use the configured percentage of the JVM memory size. */ int maxMemoryPercent = configManager.getInt(EnvironmentParams.MAX_MEMORY_PERCENT); newMaxMemory = (maxMemoryPercent * jvmMemory) / 100; } /* * Calculate the memory budget for log buffering. If the LOG_MEM_SIZE * parameter is not set, start by using 7% (1/16th) of the cache * size. If it is set, use that explicit setting. * * No point in having more log buffers than the maximum size. If * this starting point results in overly large log buffers, * reduce the log buffer budget again. */ long newLogBufferBudget = configManager.getLong(EnvironmentParams.LOG_MEM_SIZE); if (newLogBufferBudget == 0) { newLogBufferBudget = newMaxMemory >> 4; } else if (newLogBufferBudget > newMaxMemory / 2) { newLogBufferBudget = newMaxMemory / 2; } /* * We have a first pass at the log buffer budget. See what * size log buffers result. Don't let them be too big, it would * be a waste. */ int numBuffers = configManager.getInt(EnvironmentParams.NUM_LOG_BUFFERS); long startingBufferSize = newLogBufferBudget / numBuffers; int logBufferSize = configManager.getInt(EnvironmentParams.LOG_BUFFER_MAX_SIZE); if (startingBufferSize > logBufferSize) { startingBufferSize = logBufferSize; newLogBufferBudget = numBuffers * startingBufferSize; } else if (startingBufferSize < EnvironmentParams.MIN_LOG_BUFFER_SIZE) { startingBufferSize = EnvironmentParams.MIN_LOG_BUFFER_SIZE; newLogBufferBudget = numBuffers * startingBufferSize; } long newCriticalThreshold = (newMaxMemory * envImpl.getConfigManager().getInt(EnvironmentParams.EVICTOR_CRITICAL_PERCENTAGE)) / 100; long newTrackerBudget = (newMaxMemory * envImpl .getConfigManager() .getInt(EnvironmentParams.CLEANER_DETAIL_MAX_MEMORY_PERCENTAGE)) / 100; /* * If all has gone well, update the budget fields. Once the log buffer * budget is determined, the remainder of the memory is left for tree * nodes. */ maxMemory = newMaxMemory; criticalThreshold = newCriticalThreshold; logBufferBudget = newLogBufferBudget; trackerBudget = true ? newTrackerBudget : newMaxMemory; cacheBudget = newMaxMemory - newLogBufferBudget; nLockTables = configManager.getInt(EnvironmentParams.N_LOCK_TABLES); lockMemoryUsage = new long[nLockTables]; }