/**
   * Changes the mutable config properties that are present in the given config, and notifies all
   * config observer.
   */
  public synchronized void setMutableConfig(EnvironmentMutableConfig config)
      throws DatabaseException {

    /* Clone the current config. */
    EnvironmentConfig newConfig = DbInternal.cloneConfig(configManager.getEnvironmentConfig());

    /* Copy in the mutable props. */
    DbInternal.copyMutablePropsTo(config, newConfig);

    /*
     * Update the current config and notify observers. The config manager is
     * replaced with a new instance that uses the new configuration. This
     * avoid synchronization issues: other threads that have a referenced to
     * the old configuration object are not impacted.
     *
     * Notify listeners in reverse order of registration so that the
     * environment listener is notified last and it can start daemon threads
     * after they are configured.
     */
    configManager = new DbConfigManager(newConfig);
    for (int i = configObservers.size() - 1; i >= 0; i -= 1) {
      EnvConfigObserver o = (EnvConfigObserver) configObservers.get(i);
      o.envConfigUpdate(configManager);
    }
  }
  /** Throws an exception if an immutable property is changed. */
  public void checkImmutablePropsForEquality(EnvironmentConfig config)
      throws IllegalArgumentException {

    DbInternal.checkImmutablePropsForEquality(configManager.getEnvironmentConfig(), config);
  }
  /**
   * 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;
    }
  }
 /** Clones the current mutable configuration. */
 public EnvironmentMutableConfig cloneMutableConfig() {
   return DbInternal.cloneMutableConfig(configManager.getEnvironmentConfig());
 }
Example #5
0
  /** 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];
  }