mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Fabio Pistolesi
10.55.2015 876f44ddc3c09c83da4c92db890a83ea5c9aa962
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/api/DiskSpaceMonitorHandler.java
@@ -27,7 +27,8 @@
package org.opends.server.api;
import org.opends.server.extensions.DiskSpaceMonitor;
import java.io.File;
/**
 * This interface defines the set of methods that must be implemented
@@ -40,22 +41,26 @@
  /**
   * Notifies that the registered "low" threshold have been reached.
   *
   * @param monitor The DiskSpaceMonitor that detected this event.
   * @param directory the directory for which the threshold has been triggered
   * @param thresholdInBytes the threshold value in bytes
   */
  void diskLowThresholdReached(DiskSpaceMonitor monitor);
  void diskLowThresholdReached(File directory, long thresholdInBytes);
  /**
   * Notifies that the registered "full" threshold have been reached.
   *
   * @param monitor The DiskSpaceMonitor that detected this event.
   * @param directory the directory for which the threshold has been triggered
   * @param thresholdInBytes the threshold value in bytes
   */
  void diskFullThresholdReached(DiskSpaceMonitor monitor);
  void diskFullThresholdReached(File directory, long thresholdInBytes);
  /**
   * Notifies that the free disk space is now above both "low" and
   * "full" thresholds.
   * Notifies that the free disk space is now above both "low" and "full" thresholds.
   *
   * @param monitor The DiskSpaceMonitor that detected this event.
   * @param directory the directory for which the threshold has been triggeredTODO
   *
   * @param lowThresholdInBytes the low threshold value in bytes
   * @param fullThresholdInBytes the full threshold value in bytes
   */
  void diskSpaceRestored(DiskSpaceMonitor monitor);
  void diskSpaceRestored(File directory, long lowThresholdInBytes, long fullThresholdInBytes);
}
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/BackendImpl.java
@@ -27,7 +27,6 @@
package org.opends.server.backends.jeb;
import static com.sleepycat.je.EnvironmentConfig.*;
import static org.opends.messages.BackendMessages.*;
import static org.opends.messages.JebMessages.*;
import static org.opends.server.backends.jeb.ConfigurableEnvironment.*;
@@ -58,6 +57,7 @@
import org.opends.server.api.MonitorProvider;
import org.opends.server.backends.RebuildConfig;
import org.opends.server.backends.VerifyConfig;
import org.opends.server.backends.pluggable.spi.StorageStatus;
import org.opends.server.core.*;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.types.*;
@@ -91,6 +91,7 @@
  private MonitorProvider<?> rootContainerMonitor;
  private DiskSpaceMonitor diskMonitor;
  private StorageStatus storageStatus = StorageStatus.working();
  /**
   * The controls supported by this backend.
@@ -159,6 +160,7 @@
    this.cfg = cfg;
    baseDNs = this.cfg.getBaseDN().toArray(new DN[0]);
    diskMonitor = serverContext.getDiskSpaceMonitor();
  }
  /** {@inheritDoc} */
@@ -206,11 +208,8 @@
    DirectoryServer.registerMonitorProvider(rootContainerMonitor);
    // Register as disk space monitor handler
    diskMonitor = newDiskMonitor(cfg);
    if (diskMonitor != null)
    {
      DirectoryServer.registerMonitorProvider(diskMonitor);
    }
    diskMonitor.registerMonitoredDirectory(getBackendID(), getDirectory(), cfg.getDiskLowThreshold(),
        cfg.getDiskFullThreshold(), this);
    //Register as an AlertGenerator.
    DirectoryServer.registerAlertGenerator(this);
@@ -218,16 +217,10 @@
    cfg.addLocalDBChangeListener(this);
  }
  private DiskSpaceMonitor newDiskMonitor(LocalDBBackendCfg cfg) throws ConfigException, InitializationException
  private File getDirectory()
  {
    File parentDirectory = getFileForPath(cfg.getDBDirectory());
    File backendDirectory =
        new File(parentDirectory, cfg.getBackendId());
    DiskSpaceMonitor dm = new DiskSpaceMonitor(getBackendID() + " backend",
        backendDirectory, cfg.getDiskLowThreshold(), cfg.getDiskFullThreshold(),
        5, TimeUnit.SECONDS, this);
    dm.initializeMonitorProvider(null);
    return dm;
    return new File(parentDirectory, cfg.getBackendId());
  }
  /** {@inheritDoc} */
@@ -250,8 +243,7 @@
    }
    DirectoryServer.deregisterMonitorProvider(rootContainerMonitor);
    DirectoryServer.deregisterMonitorProvider(diskMonitor);
    diskMonitor.deregisterMonitoredDirectory(getDirectory(), this);
    // We presume the server will prevent more operations coming into this
    // backend, but there may be existing operations already in the
    // backend. We need to wait for them to finish.
@@ -717,7 +709,7 @@
      }
      final EnvironmentConfig envConfig = getEnvConfigForImport();
      final Importer importer = new Importer(importConfig, cfg, envConfig);
      final Importer importer = new Importer(importConfig, cfg, envConfig, serverContext);
      rootContainer = initializeRootContainer(envConfig);
      return importer.processImport(rootContainer);
    }
@@ -859,7 +851,7 @@
        envConfig = parseConfigEntry(cfg);
      }
      final Importer importer = new Importer(rebuildConfig, cfg, envConfig);
      final Importer importer = new Importer(rebuildConfig, cfg, envConfig, serverContext);
      importer.rebuildIndexes(rootContainer);
    }
    catch (ExecutionException execEx)
@@ -1002,10 +994,7 @@
        baseDNs = newBaseDNsArray;
      }
      if (diskMonitor != null)
      {
        updateDiskMonitor(diskMonitor, newCfg);
      }
      updateDiskMonitor(diskMonitor, newCfg);
      // Put the new configuration in place.
      this.cfg = newCfg;
@@ -1020,8 +1009,8 @@
  private void updateDiskMonitor(DiskSpaceMonitor dm, LocalDBBackendCfg newCfg)
  {
    dm.setFullThreshold(newCfg.getDiskFullThreshold());
    dm.setLowThreshold(newCfg.getDiskLowThreshold());
    diskMonitor.registerMonitoredDirectory(getBackendID(), getDirectory(), newCfg.getDiskLowThreshold(),
        newCfg.getDiskFullThreshold(), this);
  }
  private void removeDeletedBaseDNs(SortedSet<DN> newBaseDNs) throws DirectoryException
@@ -1196,34 +1185,30 @@
  /** {@inheritDoc} */
  @Override
  public void diskLowThresholdReached(DiskSpaceMonitor monitor) {
    LocalizableMessage msg = ERR_JEB_DISK_LOW_THRESHOLD_REACHED.get(
        monitor.getDirectory().getPath(), cfg.getBackendId(), monitor.getFreeSpace(),
        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_SPACE_LOW, msg);
  public void diskLowThresholdReached(File directory, long thresholdInBytes) {
    storageStatus = StorageStatus.lockedDown(
        WARN_DISK_SPACE_LOW_THRESHOLD_CROSSED.get(directory.getFreeSpace(), directory.getAbsolutePath(),
        thresholdInBytes, getBackendID()));
  }
  /** {@inheritDoc} */
  @Override
  public void diskFullThresholdReached(DiskSpaceMonitor monitor) {
    LocalizableMessage msg = ERR_JEB_DISK_FULL_THRESHOLD_REACHED.get(
        monitor.getDirectory().getPath(), cfg.getBackendId(), monitor.getFreeSpace(),
        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_FULL, msg);
  public void diskFullThresholdReached(File directory, long thresholdInBytes) {
    storageStatus = StorageStatus.unusable(
        WARN_DISK_SPACE_FULL_THRESHOLD_CROSSED.get(directory.getFreeSpace(), directory.getAbsolutePath(),
        thresholdInBytes, getBackendID()));
  }
  /** {@inheritDoc} */
  @Override
  public void diskSpaceRestored(DiskSpaceMonitor monitor) {
    logger.error(NOTE_JEB_DISK_SPACE_RESTORED, monitor.getFreeSpace(),
        monitor.getDirectory().getPath(), cfg.getBackendId(),
        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
  public void diskSpaceRestored(File directory, long lowThresholdInBytes, long fullThresholdInBytes) {
    storageStatus = StorageStatus.working();
  }
  private void checkDiskSpace(Operation operation) throws DirectoryException
  {
    if(diskMonitor.isFullThresholdReached() ||
        (diskMonitor.isLowThresholdReached()
    if(storageStatus.isUnusable() ||
        (storageStatus.isLockedDown()
            && operation != null
            && !operation.getClientConnection().hasPrivilege(
                Privilege.BYPASS_LOCKDOWN, operation)))
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/Importer.java
@@ -27,7 +27,6 @@
package org.opends.server.backends.jeb;
import static com.sleepycat.je.EnvironmentConfig.*;
import static org.opends.messages.JebMessages.*;
import static org.opends.server.admin.std.meta.LocalDBIndexCfgDefn.IndexType.*;
import static org.opends.server.backends.jeb.IndexOutputBuffer.*;
@@ -84,7 +83,7 @@
import java.util.concurrent.atomic.AtomicLong;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg3;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteString;
@@ -98,6 +97,7 @@
import org.opends.server.backends.RebuildConfig;
import org.opends.server.backends.RebuildConfig.RebuildMode;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ServerContext;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
@@ -162,6 +162,8 @@
  private static final int MIN_READ_AHEAD_CACHE_SIZE = 2 * KB;
  /** Small heap threshold used to give more memory to JVM to attempt OOM errors. */
  private static final int SMALL_HEAP_SIZE = 256 * MB;
  /** Minimum memory needed for import */
  private static final int MINIMUM_AVAILABLE_MEMORY = 32 * MB;
  /** The DN attribute type. */
  private static final AttributeType dnType;
@@ -267,6 +269,8 @@
  /** Number of phase one buffers. */
  private int phaseOneBufferCount;
  private final DiskSpaceMonitor diskSpaceMonitor;
  static
  {
    AttributeType attrType = DirectoryServer.getAttributeType("dn");
@@ -286,6 +290,8 @@
   *          The local DB back-end configuration.
   * @param envConfig
   *          The JEB environment config.
   * @param serverContext
   *          The ServerContext for this Directory Server instance
   * @throws InitializationException
   *           If a problem occurs during initialization.
   * @throws JebException
@@ -293,14 +299,15 @@
   * @throws ConfigException
   *           If a problem occurs during initialization.
   */
  public Importer(RebuildConfig rebuildConfig, LocalDBBackendCfg cfg,
      EnvironmentConfig envConfig) throws InitializationException,
  public Importer(RebuildConfig rebuildConfig, LocalDBBackendCfg cfg, EnvironmentConfig envConfig,
      ServerContext serverContext) throws InitializationException,
      JebException, ConfigException
  {
    this.importConfiguration = null;
    this.backendConfiguration = cfg;
    this.tmpEnv = null;
    this.threadCount = 1;
    this.diskSpaceMonitor = serverContext.getDiskSpaceMonitor();
    this.rebuildManager = new RebuildIndexManager(rebuildConfig, cfg);
    this.indexCount = rebuildManager.getIndexCount();
    this.clearedBackend = false;
@@ -327,6 +334,8 @@
   *          The local DB back-end configuration.
   * @param envConfig
   *          The JEB environment config.
   * @param serverContext
   *          The ServerContext for this Directory Server instance
   * @throws InitializationException
   *           If a problem occurs during initialization.
   * @throws ConfigException
@@ -334,13 +343,14 @@
   * @throws DatabaseException
   *           If an error occurred when opening the DB.
   */
  public Importer(LDIFImportConfig importConfiguration,
      LocalDBBackendCfg localDBBackendCfg, EnvironmentConfig envConfig)
  public Importer(LDIFImportConfig importConfiguration, LocalDBBackendCfg localDBBackendCfg,
      EnvironmentConfig envConfig, ServerContext serverContext)
      throws InitializationException, ConfigException, DatabaseException
  {
    this.rebuildManager = null;
    this.importConfiguration = importConfiguration;
    this.backendConfiguration = localDBBackendCfg;
    this.diskSpaceMonitor = serverContext.getDiskSpaceMonitor();
    if (importConfiguration.getThreadCount() == 0)
    {
@@ -625,8 +635,8 @@
        configuredMemory = backendConfiguration.getDBCachePercent() * Runtime.getRuntime().maxMemory() / 100;
      }
      // Round up to minimum of 16MB (e.g. unit tests only use 2% cache).
      totalAvailableMemory = Math.max(Math.min(usableMemory, configuredMemory), 16 * MB);
      // Round up to minimum of 32MB (e.g. unit tests only use a small cache).
      totalAvailableMemory = Math.max(Math.min(usableMemory, configuredMemory), MINIMUM_AVAILABLE_MEMORY);
    }
    else
    {
@@ -860,14 +870,10 @@
    this.rootContainer = rootContainer;
    long startTime = System.currentTimeMillis();
    DiskSpaceMonitor tmpMonitor = createDiskSpaceMonitor(tempDir, "backend index rebuild tmp directory");
    tmpMonitor.initializeMonitorProvider(null);
    DirectoryServer.registerMonitorProvider(tmpMonitor);
    updateDiskMonitor(tempDir, "backend index rebuild tmp directory");
    File parentDirectory = getFileForPath(backendConfiguration.getDBDirectory());
    File backendDirectory = new File(parentDirectory, backendConfiguration.getBackendId());
    DiskSpaceMonitor dbMonitor = createDiskSpaceMonitor(backendDirectory, "backend index rebuild DB directory");
    dbMonitor.initializeMonitorProvider(null);
    DirectoryServer.registerMonitorProvider(dbMonitor);
    updateDiskMonitor(backendDirectory, "backend index rebuild DB directory");
    try
    {
@@ -879,10 +885,8 @@
    }
    finally
    {
      DirectoryServer.deregisterMonitorProvider(tmpMonitor);
      DirectoryServer.deregisterMonitorProvider(dbMonitor);
      tmpMonitor.finalizeMonitorProvider();
      dbMonitor.finalizeMonitorProvider();
      diskSpaceMonitor.deregisterMonitoredDirectory(tempDir, this);
      diskSpaceMonitor.deregisterMonitoredDirectory(backendDirectory, this);
    }
  }
@@ -908,8 +912,8 @@
      InterruptedException, ExecutionException
  {
    this.rootContainer = rootContainer;
    DiskSpaceMonitor tmpMonitor = null;
    DiskSpaceMonitor dbMonitor = null;
    File parentDirectory = getFileForPath(backendConfiguration.getDBDirectory());
    File backendDirectory = new File(parentDirectory, backendConfiguration.getBackendId());
    try {
      try
      {
@@ -921,14 +925,8 @@
        throw new InitializationException(message, ioe);
      }
      tmpMonitor = createDiskSpaceMonitor(tempDir, "backend import tmp directory");
      tmpMonitor.initializeMonitorProvider(null);
      DirectoryServer.registerMonitorProvider(tmpMonitor);
      File parentDirectory = getFileForPath(backendConfiguration.getDBDirectory());
      File backendDirectory = new File(parentDirectory, backendConfiguration.getBackendId());
      dbMonitor = createDiskSpaceMonitor(backendDirectory, "backend import DB directory");
      dbMonitor.initializeMonitorProvider(null);
      DirectoryServer.registerMonitorProvider(dbMonitor);
      updateDiskMonitor(tempDir, "backend import tmp directory");
      updateDiskMonitor(backendDirectory, "backend import DB directory");
      logger.info(NOTE_JEB_IMPORT_STARTING, DirectoryServer.getVersionString(),
              BUILD_ID, REVISION_NUMBER);
@@ -991,24 +989,15 @@
          // Do nothing.
        }
      }
      if (tmpMonitor != null)
      {
        DirectoryServer.deregisterMonitorProvider(tmpMonitor);
        tmpMonitor.finalizeMonitorProvider();
      }
      if (dbMonitor != null)
      {
        DirectoryServer.deregisterMonitorProvider(dbMonitor);
        dbMonitor.finalizeMonitorProvider();
      }
      diskSpaceMonitor.deregisterMonitoredDirectory(tempDir, this);
      diskSpaceMonitor.deregisterMonitoredDirectory(backendDirectory, this);
    }
  }
  private DiskSpaceMonitor createDiskSpaceMonitor(File dir, String backendSuffix)
  private void updateDiskMonitor(File dir, String backendSuffix)
  {
    final LocalDBBackendCfg cfg = backendConfiguration;
    return new DiskSpaceMonitor(cfg.getBackendId() + " " + backendSuffix, dir,
        cfg.getDiskLowThreshold(), cfg.getDiskFullThreshold(), 5, TimeUnit.SECONDS, this);
    diskSpaceMonitor.registerMonitoredDirectory(backendConfiguration.getBackendId() + " " + backendSuffix, dir,
        backendConfiguration.getDiskLowThreshold(), backendConfiguration.getDiskFullThreshold(), this);
  }
  private void recursiveDelete(File dir)
@@ -3643,21 +3632,20 @@
    }
    @Override
    public void diskLowThresholdReached(DiskSpaceMonitor monitor)
    public void diskLowThresholdReached(File directory, long thresholdInBytes)
    {
      diskFullThresholdReached(monitor);
      diskFullThresholdReached(directory, thresholdInBytes);
    }
    @Override
    public void diskFullThresholdReached(DiskSpaceMonitor monitor)
    public void diskFullThresholdReached(File directory, long thresholdInBytes)
    {
      isCanceled = true;
      logger.error(ERR_REBUILD_INDEX_LACK_DISK, monitor.getDirectory().getPath(),
              monitor.getFreeSpace(), monitor.getLowThreshold());
      logger.error(ERR_REBUILD_INDEX_LACK_DISK, directory.getAbsolutePath(), thresholdInBytes);
    }
    @Override
    public void diskSpaceRestored(DiskSpaceMonitor monitor)
    public void diskSpaceRestored(File directory, long lowThresholdInBytes, long fullThresholdInBytes)
    {
      // Do nothing
    }
@@ -4406,25 +4394,25 @@
  /** {@inheritDoc} */
  @Override
  public void diskLowThresholdReached(DiskSpaceMonitor monitor)
  public void diskLowThresholdReached(File directory, long thresholdInBytes)
  {
    diskFullThresholdReached(monitor);
    diskFullThresholdReached(directory, thresholdInBytes);
  }
  /** {@inheritDoc} */
  @Override
  public void diskFullThresholdReached(DiskSpaceMonitor monitor)
  public void diskFullThresholdReached(File directory, long thresholdInBytes)
  {
    isCanceled = true;
    Arg3<Object, Number, Number> argMsg = !isPhaseOneDone
    Arg2<Object, Number> argMsg = !isPhaseOneDone
        ? ERR_IMPORT_LDIF_LACK_DISK_PHASE_ONE
        : ERR_IMPORT_LDIF_LACK_DISK_PHASE_TWO;
    logger.error(argMsg.get(monitor.getDirectory().getPath(), monitor.getFreeSpace(), monitor.getLowThreshold()));
    logger.error(argMsg.get(directory.getAbsolutePath(), thresholdInBytes));
  }
  /** {@inheritDoc} */
  @Override
  public void diskSpaceRestored(DiskSpaceMonitor monitor)
  public void diskSpaceRestored(File directory, long lowThresholdInBytes, long fullThresholdInBytes)
  {
    // Do nothing.
  }
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java
@@ -27,7 +27,6 @@
import static com.persistit.Transaction.CommitPolicy.*;
import static java.util.Arrays.*;
import static org.opends.messages.BackendMessages.*;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.messages.JebMessages.*;
@@ -37,10 +36,8 @@
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -50,7 +47,6 @@
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.PersistitBackendCfg;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.DiskSpaceMonitorHandler;
import org.opends.server.backends.pluggable.spi.Cursor;
import org.opends.server.backends.pluggable.spi.Importer;
@@ -66,7 +62,6 @@
import org.opends.server.core.MemoryQuota;
import org.opends.server.core.ServerContext;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.types.DN;
import org.opends.server.types.FilePermission;
import com.persistit.Configuration;
@@ -86,7 +81,7 @@
/** PersistIt database implementation of the {@link Storage} engine. */
@SuppressWarnings("javadoc")
public final class PersistItStorage implements Storage, ConfigurationChangeListener<PersistitBackendCfg>,
  DiskSpaceMonitorHandler, AlertGenerator
  DiskSpaceMonitorHandler
{
  private static final String VOLUME_NAME = "dj";
  /** The buffer / page size used by the PersistIt storage. */
@@ -505,6 +500,7 @@
  private PersistitBackendCfg config;
  private DiskSpaceMonitor diskMonitor;
  private MemoryQuota memQuota;
  private StorageStatus storageStatus = StorageStatus.working();
  /**
   * Creates a new persistit storage with the provided configuration.
@@ -528,6 +524,7 @@
    final BufferPoolConfiguration bufferPoolCfg = getBufferPoolCfg();
    bufferPoolCfg.setMaximumCount(Integer.MAX_VALUE);
    diskMonitor = serverContext.getDiskSpaceMonitor();
    memQuota = serverContext.getMemoryQuota();
    if (cfg.getDBCacheSize() > 0)
    {
@@ -568,8 +565,7 @@
      memQuota.releaseMemory(memQuota.memPercentToBytes(config.getDBCachePercent()));
    }
    config.removePersistitChangeListener(this);
    DirectoryServer.deregisterMonitorProvider(diskMonitor);
    DirectoryServer.deregisterAlertGenerator(this);
    diskMonitor.deregisterMonitoredDirectory(getDirectory(), this);
  }
  private BufferPoolConfiguration getBufferPoolCfg()
@@ -598,11 +594,12 @@
    {
      throw new StorageRuntimeException(e);
    }
    // Register as disk space monitor handler
    diskMonitor = newDiskMonitor(config);
    DirectoryServer.registerMonitorProvider(diskMonitor);
    //Register as an AlertGenerator.
    DirectoryServer.registerAlertGenerator(this);
    diskMonitor.registerMonitoredDirectory(
        config.getBackendId() + " backend",
        getDirectory(),
        config.getDiskLowThreshold(),
        config.getDiskFullThreshold(),
        this);
  }
  /** {@inheritDoc} */
@@ -968,9 +965,12 @@
        setDBDirPermissions(cfg, newBackendDirectory);
      }
      diskMonitor.setFullThreshold(cfg.getDiskFullThreshold());
      diskMonitor.setLowThreshold(cfg.getDiskLowThreshold());
      diskMonitor.registerMonitoredDirectory(
        config.getBackendId() + " backend",
        getDirectory(),
        cfg.getDiskLowThreshold(),
        cfg.getDiskFullThreshold(),
        this);
      config = cfg;
    }
    catch (Exception e)
@@ -1037,74 +1037,29 @@
  @Override
  public StorageStatus getStorageStatus()
  {
    if (diskMonitor.isFullThresholdReached())
    {
      return StorageStatus.unusable(WARN_JEB_OUT_OF_DISK_SPACE.get());
    }
    if (diskMonitor.isLowThresholdReached())
    {
      return StorageStatus.lockedDown(WARN_JEB_OUT_OF_DISK_SPACE.get());
    }
    return StorageStatus.working();
    return storageStatus;
  }
  /** {@inheritDoc} */
  @Override
  public void diskFullThresholdReached(DiskSpaceMonitor monitor) {
    LocalizableMessage msg = ERR_JEB_DISK_FULL_THRESHOLD_REACHED.get(
        monitor.getDirectory().getPath(), config.getBackendId(), monitor.getFreeSpace(),
        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_FULL, msg);
  public void diskFullThresholdReached(File directory, long thresholdInBytes) {
    storageStatus = StorageStatus.unusable(
        WARN_DISK_SPACE_FULL_THRESHOLD_CROSSED.get(directory.getFreeSpace(), directory.getAbsolutePath(),
        thresholdInBytes, config.getBackendId()));
  }
  /** {@inheritDoc} */
  @Override
  public void diskLowThresholdReached(DiskSpaceMonitor monitor) {
    LocalizableMessage msg = ERR_JEB_DISK_LOW_THRESHOLD_REACHED.get(
        monitor.getDirectory().getPath(), config.getBackendId(), monitor.getFreeSpace(),
        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_SPACE_LOW, msg);
  public void diskLowThresholdReached(File directory, long thresholdInBytes) {
    storageStatus = StorageStatus.lockedDown(
        WARN_DISK_SPACE_LOW_THRESHOLD_CROSSED.get(directory.getFreeSpace(), directory.getAbsolutePath(),
        thresholdInBytes, config.getBackendId()));
  }
  /** {@inheritDoc} */
  @Override
  public void diskSpaceRestored(DiskSpaceMonitor monitor) {
    logger.error(NOTE_JEB_DISK_SPACE_RESTORED, monitor.getFreeSpace(),
        monitor.getDirectory().getPath(), config.getBackendId(),
        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
  }
  private DiskSpaceMonitor newDiskMonitor(PersistitBackendCfg config) throws Exception
  {
    File parentDirectory = getFileForPath(config.getDBDirectory());
    File backendDirectory = new File(parentDirectory, config.getBackendId());
    DiskSpaceMonitor dm = new DiskSpaceMonitor(config.getBackendId() + " backend",
        backendDirectory, config.getDiskLowThreshold(), config.getDiskFullThreshold(),
        5, TimeUnit.SECONDS, this);
    dm.initializeMonitorProvider(null);
    return dm;
  }
  /** {@inheritDoc} */
  @Override
  public DN getComponentEntryDN() {
    return config.dn();
  }
  /** {@inheritDoc} */
  @Override
  public String getClassName() {
    return PersistItStorage.class.getName();
  }
  /** {@inheritDoc} */
  @Override
  public Map<String, String> getAlerts()
  {
    Map<String, String> alerts = new LinkedHashMap<String, String>();
    alerts.put(ALERT_TYPE_DISK_SPACE_LOW, ALERT_DESCRIPTION_DISK_SPACE_LOW);
    alerts.put(ALERT_TYPE_DISK_FULL, ALERT_DESCRIPTION_DISK_FULL);
    return alerts;
  public void diskSpaceRestored(File directory, long lowThresholdInBytes, long fullThresholdInBytes) {
    storageStatus = StorageStatus.working();
  }
}
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java
@@ -84,7 +84,6 @@
import java.util.concurrent.atomic.AtomicLong;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg3;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
@@ -98,7 +97,6 @@
import org.opends.server.admin.std.server.BackendIndexCfg;
import org.opends.server.admin.std.server.PersistitBackendCfg;
import org.opends.server.admin.std.server.PluggableBackendCfg;
import org.opends.server.api.DiskSpaceMonitorHandler;
import org.opends.server.backends.RebuildConfig;
import org.opends.server.backends.RebuildConfig.RebuildMode;
import org.opends.server.backends.persistit.PersistItStorage;
@@ -114,7 +112,6 @@
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ServerContext;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
@@ -128,7 +125,7 @@
 * This class provides the engine that performs both importing of LDIF files and
 * the rebuilding of indexes.
 */
final class Importer implements DiskSpaceMonitorHandler
final class Importer
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
@@ -2781,7 +2778,7 @@
  /**
   * The rebuild index manager handles all rebuild index related processing.
   */
  private class RebuildIndexManager extends ImportTask implements DiskSpaceMonitorHandler
  private class RebuildIndexManager extends ImportTask
  {
    /** Rebuild index configuration. */
@@ -3402,26 +3399,6 @@
    {
      return this.totalEntries;
    }
    @Override
    public void diskLowThresholdReached(DiskSpaceMonitor monitor)
    {
      diskFullThresholdReached(monitor);
    }
    @Override
    public void diskFullThresholdReached(DiskSpaceMonitor monitor)
    {
      isCanceled = true;
      logger.error(ERR_REBUILD_INDEX_LACK_DISK, monitor.getDirectory().getPath(),
              monitor.getFreeSpace(), monitor.getLowThreshold());
    }
    @Override
    public void diskSpaceRestored(DiskSpaceMonitor monitor)
    {
      // Do nothing
    }
  }
  /**
@@ -4035,29 +4012,4 @@
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public void diskLowThresholdReached(DiskSpaceMonitor monitor)
  {
    diskFullThresholdReached(monitor);
  }
  /** {@inheritDoc} */
  @Override
  public void diskFullThresholdReached(DiskSpaceMonitor monitor)
  {
    isCanceled = true;
    Arg3<Object, Number, Number> argMsg = !isPhaseOneDone
        ? ERR_IMPORT_LDIF_LACK_DISK_PHASE_ONE
        : ERR_IMPORT_LDIF_LACK_DISK_PHASE_TWO;
    logger.error(argMsg.get(monitor.getDirectory().getPath(), monitor.getFreeSpace(), monitor.getLowThreshold()));
  }
  /** {@inheritDoc} */
  @Override
  public void diskSpaceRestored(DiskSpaceMonitor monitor)
  {
    // Do nothing.
  }
}
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -136,6 +136,7 @@
import org.opends.server.crypto.CryptoManagerImpl;
import org.opends.server.crypto.CryptoManagerSync;
import org.opends.server.extensions.ConfigFileHandler;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.extensions.JMXAlertHandler;
import org.opends.server.loggers.AccessLogger;
import org.opends.server.loggers.DebugLogPublisher;
@@ -797,6 +798,9 @@
  /** The memory reservation system */
  private MemoryQuota memoryQuota;
  /** The Disk Space Monitor */
  private DiskSpaceMonitor diskSpaceMonitor;
  /**
   * The maximum size that internal buffers will be allowed to grow to until
   * they are trimmed.
@@ -898,6 +902,12 @@
    {
      return directoryServer.memoryQuota;
    }
    @Override
    public DiskSpaceMonitor getDiskSpaceMonitor()
    {
      return directoryServer.diskSpaceMonitor;
    }
  }
@@ -930,6 +940,7 @@
    serverContext = new DirectoryServerContext();
    virtualAttributeConfigManager = new VirtualAttributeConfigManager(serverContext);
    memoryQuota = new MemoryQuota();
    diskSpaceMonitor = new DiskSpaceMonitor();
  }
@@ -1470,6 +1481,8 @@
      // Determine whether or not we should start the connection handlers.
      boolean startConnectionHandlers = !environmentConfig.disableConnectionHandlers();
      diskSpaceMonitor.startDiskSpaceMonitor();
      initializeSchema();
      // Allow internal plugins to be registered.
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
@@ -26,6 +26,7 @@
package org.opends.server.core;
import org.forgerock.opendj.config.server.ServerManagementContext;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.schema.SchemaUpdater;
import org.opends.server.types.DirectoryEnvironmentConfig;
import org.opends.server.types.Schema;
@@ -86,4 +87,13 @@
   * @return the memory quota system
   */
  MemoryQuota getMemoryQuota();
  /**
   * Returns the Disk Space Monitoring service, for checking free disk space.
   * Configure a directory to be monitored and optionally get alerted when
   * disk space transitions from low to full to back to normal.
   *
   * @return the Disk Space Monioring service
   */
  DiskSpaceMonitor getDiskSpaceMonitor();
}
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/extensions/DiskSpaceMonitor.java
@@ -28,23 +28,39 @@
import static org.opends.messages.CoreMessages.*;
import static org.opends.server.core.DirectoryServer.*;
import static org.opends.server.util.ServerConstants.ALERT_DESCRIPTION_DISK_FULL;
import static org.opends.server.util.ServerConstants.ALERT_DESCRIPTION_DISK_SPACE_LOW;
import static org.opends.server.util.ServerConstants.ALERT_TYPE_DISK_FULL;
import static org.opends.server.util.ServerConstants.ALERT_TYPE_DISK_SPACE_LOW;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.admin.std.server.MonitorProviderCfg;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.DiskSpaceMonitorHandler;
import org.opends.server.api.MonitorProvider;
import org.opends.server.api.ServerShutdownListener;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
import org.opends.server.util.Platform;
/**
 * This class provides an application-wide disk space monitoring service.
@@ -56,243 +72,428 @@
 * have been reached, the handler will not be notified again until the
 * free space raises above the "low" threshold.
 */
public class DiskSpaceMonitor extends MonitorProvider<MonitorProviderCfg>
    implements Runnable
public class DiskSpaceMonitor extends MonitorProvider<MonitorProviderCfg> implements Runnable, AlertGenerator,
    ServerShutdownListener
{
  /**
   * Helper class for each requestor for use with cn=monitor reporting and users of a spcific mountpoint.
   */
  private class MonitoredDirectory extends MonitorProvider<MonitorProviderCfg>
  {
    private volatile File directory;
    private volatile long lowThreshold;
    private volatile long fullThreshold;
    private final DiskSpaceMonitorHandler handler;
    private final String instanceName;
    private final String baseName;
    private int lastState;
    private MonitoredDirectory(File directory, String instanceName, String baseName, DiskSpaceMonitorHandler handler)
    {
      this.directory = directory;
      this.instanceName = instanceName;
      this.baseName = baseName;
      this.handler = handler;
    }
    /** {@inheritDoc} */
    @Override
    public String getMonitorInstanceName() {
      return instanceName + "," + "cn=" + baseName;
    }
    /** {@inheritDoc} */
    @Override
    public void initializeMonitorProvider(MonitorProviderCfg configuration)
        throws ConfigException, InitializationException {
    }
    /** {@inheritDoc} */
    @Override
    public List<Attribute> getMonitorData() {
      final List<Attribute> monitorAttrs = new ArrayList<Attribute>();
      monitorAttrs.add(attr("disk-dir", getDefaultStringSyntax(), directory.getPath()));
      monitorAttrs.add(attr("disk-free", getDefaultIntegerSyntax(), getFreeSpace()));
      monitorAttrs.add(attr("disk-state", getDefaultStringSyntax(), getState()));
      return monitorAttrs;
    }
    private File getDirectory() {
      return directory;
    }
    private long getFreeSpace() {
      return directory.getUsableSpace();
    }
    private long getFullThreshold() {
      return fullThreshold;
    }
    private long getLowThreshold() {
      return lowThreshold;
    }
    private void setFullThreshold(long fullThreshold) {
      this.fullThreshold = fullThreshold;
    }
    private void setLowThreshold(long lowThreshold) {
      this.lowThreshold = lowThreshold;
    }
    private Attribute attr(String name, AttributeSyntax<?> syntax, Object value)
    {
      AttributeType attrType = DirectoryServer.getDefaultAttributeType(name, syntax);
      return Attributes.create(attrType, String.valueOf(value));
    }
    private String getState()
    {
      switch(lastState)
      {
      case NORMAL:
        return "normal";
      case LOW:
        return "low";
      case FULL:
        return "full";
      default:
        return null;
      }
    }
  }
  /**
   * Helper class for building temporary list of handlers to notify on threshold hits.
   * One object per directory per state will hold all the handlers matching directory and state.
   */
  private class HandlerNotifier {
    private File directory;
    private int state;
    /** printable list of handlers names, for reporting backend names in alert messages */
    private final StringBuilder diskNames = new StringBuilder();
    private final List<MonitoredDirectory> allHandlers = new ArrayList<MonitoredDirectory>();
    private HandlerNotifier(File directory, int state)
    {
      this.directory = directory;
      this.state = state;
    }
    private void notifyHandlers()
    {
      for (MonitoredDirectory mdElem : allHandlers)
      {
        switch (state)
        {
        case FULL:
          mdElem.handler.diskFullThresholdReached(mdElem.getDirectory(), mdElem.getFullThreshold());
          break;
        case LOW:
          mdElem.handler.diskLowThresholdReached(mdElem.getDirectory(), mdElem.getLowThreshold());
          break;
        case NORMAL:
          mdElem.handler.diskSpaceRestored(mdElem.getDirectory(), mdElem.getLowThreshold(),
              mdElem.getFullThreshold());
          break;
        }
      }
    }
    private boolean isEmpty()
    {
      return allHandlers.size() == 0;
    }
    private void addHandler(MonitoredDirectory handler)
    {
      logger.trace("State change: %d -> %d", handler.lastState, state);
      handler.lastState = state;
      if (handler.handler != null)
      {
        allHandlers.add(handler);
      }
      appendName(diskNames, handler.instanceName);
    }
    private void appendName(StringBuilder strNames, String strVal)
    {
      if (strNames.length() > 0)
      {
        strNames.append(", ");
      }
      strNames.append(strVal);
    }
  }
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  private static final int NORMAL = 0;
  private static final int LOW = 1;
  private static final int FULL = 2;
  private volatile File directory;
  private volatile long lowThreshold;
  private volatile long fullThreshold;
  private final DiskSpaceMonitorHandler handler;
  private final int interval;
  private final TimeUnit unit;
  private final String instanceName;
  private int lastState;
  private static final String INSTANCENAME = "Disk Space Monitor";
  private final HashMap<File, List<MonitoredDirectory>> monitoredDirs =
      new HashMap<File, List<MonitoredDirectory>>();
  /**
   * Constructs a new DiskSpaceMonitor that will notify the specified
   * DiskSpaceMonitorHandler when the specified disk
   * falls below the provided thresholds.
   *
   * @param instanceName A unique name for this monitor.
   * @param directory The directory to monitor.
   * @param lowThreshold The "low" threshold.
   * @param fullThreshold   The "full" threshold.
   * @param interval  The polling interval for checking free space.
   * @param unit the time unit of the interval parameter.
   * @param handler The handler to get notified when the provided thresholds are
   *                reached or <code>null</code> if no notification is needed;
   * Constructs a new DiskSpaceMonitor that will notify registered DiskSpaceMonitorHandler objects when filesystems
   * on which configured directories reside, fall below the provided thresholds.
   */
  public DiskSpaceMonitor(String instanceName, File directory,
                          long lowThreshold,
                          long fullThreshold, int interval, TimeUnit unit,
                          DiskSpaceMonitorHandler handler) {
    this.directory = directory;
    this.lowThreshold = lowThreshold;
    this.fullThreshold = fullThreshold;
    this.interval = interval;
    this.unit = unit;
    this.handler = handler;
    this.instanceName = instanceName+",cn=Disk Space Monitor";
  }
  /**
   * Retrieves the directory currently being monitored.
   *
   * @return The directory currently being monitored.
   */
  public File getDirectory() {
    return directory;
  }
  /**
   * Sets the directory to monitor.
   *
   * @param directory The directory to monitor.
   */
  public void setDirectory(File directory) {
    this.directory = directory;
  }
  /**
   * Retrieves the currently "low" space threshold currently being enforced.
   *
   * @return The currently "low" space threshold currently being enforced.
   */
  public long getLowThreshold() {
    return lowThreshold;
  }
  /**
   * Sets the "low" space threshold to enforce.
   *
   * @param lowThreshold The "low" space threshold to enforce.
   */
  public void setLowThreshold(long lowThreshold) {
    this.lowThreshold = lowThreshold;
  }
  /**
   * Retrieves the currently full threshold currently being enforced.
   *
   * @return The currently full space threshold currently being enforced.
   */
  public long getFullThreshold() {
    return fullThreshold;
  }
  /**
   * Sets the full threshold to enforce.
   *
   * @param fullThreshold The full space threshold to enforce.
   */
  public void setFullThreshold(long fullThreshold) {
    this.fullThreshold = fullThreshold;
  }
  /**
   * Retrieves the free space currently on the disk.
   *
   * @return The free space currently on the disk.
   */
  public long getFreeSpace() {
    return directory.getUsableSpace();
  }
  /**
   * Indicates if the "full" threshold is reached.
   *
   * @return <code>true</code> if the free space is lower than the "full"
   *         threshold or <code>false</code> otherwise.
   */
  public boolean isFullThresholdReached()
  public DiskSpaceMonitor()
  {
    return lastState >= FULL;
  }
  /**
   * Indicates if the "low" threshold is reached.
   *
   * @return <code>true</code> if the free space is lower than the "low"
   *         threshold or <code>false</code> otherwise.
   * Starts periodic monitoring of all registered directories.
   */
  public boolean isLowThresholdReached()
  public void startDiskSpaceMonitor()
  {
    return lastState >= LOW;
    DirectoryServer.registerMonitorProvider(this);
    DirectoryServer.registerShutdownListener(this);
    scheduleUpdate(this, 0, 5, TimeUnit.SECONDS);
  }
  /**
   * Registers or reconfigures a directory for monitoring.
   * If possible, we will try to get and use the mountpoint where the directory resides and monitor it instead.
   * If the directory is already registered for the same <code>handler</code>, simply change its configuration.
   * @param instanceName A name for the handler, as used by cn=monitor
   * @param directory The directory to monitor
   * @param lowThresholdBytes Disk slow threshold expressed in bytes
   * @param fullThresholdBytes Disk full threshold expressed in bytes
   * @param handler The class requesting to be called when a transition in disk space occurs
   */
  public void registerMonitoredDirectory(String instanceName, File directory, long lowThresholdBytes,
      long fullThresholdBytes, DiskSpaceMonitorHandler handler)
  {
    File fsMountPoint;
    try
    {
      fsMountPoint = Platform.getFilesystem(directory);
    }
    catch (IOException ioe)
    {
      logger.warn(ERR_DISK_SPACE_GET_MOUNT_POINT, directory.getAbsolutePath(), ioe.getLocalizedMessage());
      fsMountPoint = directory;
    }
    MonitoredDirectory newDSH = new MonitoredDirectory(directory, instanceName, INSTANCENAME, handler);
    newDSH.setFullThreshold(fullThresholdBytes);
    newDSH.setLowThreshold(lowThresholdBytes);
    synchronized (monitoredDirs)
    {
      List<MonitoredDirectory> diskHelpers = monitoredDirs.get(fsMountPoint);
      if (diskHelpers == null)
      {
        List<MonitoredDirectory> newList = new ArrayList<MonitoredDirectory>();
        newList.add(newDSH);
        monitoredDirs.put(fsMountPoint, newList);
      }
      else
      {
        for (MonitoredDirectory elem : diskHelpers)
        {
          if (elem.handler.equals(handler) && elem.getDirectory().equals(directory))
          {
            elem.setFullThreshold(fullThresholdBytes);
            elem.setLowThreshold(lowThresholdBytes);
            return;
          }
        }
        diskHelpers.add(newDSH);
      }
      DirectoryServer.registerMonitorProvider(newDSH);
    }
  }
  /**
   * Removes a directory from the set of monitored directories.
   *
   * @param directory The directory to stop monitoring on
   * @param handler The class that requested monitoring
   */
  public void deregisterMonitoredDirectory(File directory, DiskSpaceMonitorHandler handler)
  {
    synchronized (monitoredDirs)
    {
      List<MonitoredDirectory> directories = monitoredDirs.get(directory);
      if (directories != null)
      {
        Iterator<MonitoredDirectory> itr = directories.iterator();
        while (itr.hasNext())
        {
          MonitoredDirectory curDirectory = itr.next();
          if (curDirectory.handler.equals(handler))
          {
            DirectoryServer.deregisterMonitorProvider(curDirectory);
            itr.remove();
          }
        }
        if (directories.isEmpty())
        {
          monitoredDirs.remove(directory);
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public void initializeMonitorProvider(MonitorProviderCfg configuration)
      throws ConfigException, InitializationException {
    scheduleUpdate(this, 0, interval, unit);
    // Not used...
  }
  /** {@inheritDoc} */
  @Override
  public String getMonitorInstanceName() {
    return instanceName;
    return INSTANCENAME;
  }
  /** {@inheritDoc} */
  @Override
  public List<Attribute> getMonitorData() {
    final ArrayList<Attribute> monitorAttrs = new ArrayList<Attribute>();
    monitorAttrs.add(attr("disk-dir", getDefaultStringSyntax(), directory.getPath()));
    monitorAttrs.add(attr("disk-free", getDefaultIntegerSyntax(), getFreeSpace()));
    monitorAttrs.add(attr("disk-state", getDefaultStringSyntax(), getState()));
    return monitorAttrs;
    return new ArrayList<Attribute>();
  }
  private Attribute attr(String name, AttributeSyntax<?> syntax, Object value)
  /** {@inheritDoc} */
  @Override
  public void run()
  {
    AttributeType attrType = DirectoryServer.getDefaultAttributeType(name, syntax);
    return Attributes.create(attrType, String.valueOf(value));
  }
    List<HandlerNotifier> diskFull = new ArrayList<HandlerNotifier>();
    List<HandlerNotifier> diskLow = new ArrayList<HandlerNotifier>();
    List<HandlerNotifier> diskRestored = new ArrayList<HandlerNotifier>();
  private String getState()
  {
    switch(lastState)
    synchronized (monitoredDirs)
    {
    case NORMAL:
      return "normal";
    case LOW:
      return "low";
    case FULL:
      return "full";
    default:
      return null;
      for (Entry<File, List<MonitoredDirectory>> dirElem : monitoredDirs.entrySet())
      {
        File directory = dirElem.getKey();
        HandlerNotifier diskFullClients = new HandlerNotifier(directory, FULL);
        HandlerNotifier diskLowClients = new HandlerNotifier(directory, LOW);
        HandlerNotifier diskRestoredClients = new HandlerNotifier(directory, NORMAL);
        try
        {
          long lastFreeSpace = directory.getUsableSpace();
          for (MonitoredDirectory handlerElem : dirElem.getValue())
          {
            if (lastFreeSpace < handlerElem.getFullThreshold() && handlerElem.lastState < FULL)
            {
              diskFullClients.addHandler(handlerElem);
            }
            else if (lastFreeSpace < handlerElem.getLowThreshold() && handlerElem.lastState < LOW)
            {
              diskLowClients.addHandler(handlerElem);
            }
            else if (handlerElem.lastState != NORMAL)
            {
              diskRestoredClients.addHandler(handlerElem);
            }
          }
          addToList(diskFull, diskFullClients);
          addToList(diskLow, diskLowClients);
          addToList(diskRestored, diskRestoredClients);
        }
        catch(Exception e)
        {
          logger.error(ERR_DISK_SPACE_MONITOR_UPDATE_FAILED, directory, e);
          logger.traceException(e);
        }
      }
    }
    // It is probably better to notify handlers outside of the synchronized section.
    sendNotification(diskFull, FULL, ALERT_DESCRIPTION_DISK_FULL);
    sendNotification(diskLow, LOW, ALERT_TYPE_DISK_SPACE_LOW);
    sendNotification(diskRestored, NORMAL, null);
  }
  private void addToList(List<HandlerNotifier> hnList, HandlerNotifier notifier)
  {
    if (!notifier.isEmpty())
    {
      hnList.add(notifier);
    }
  }
  private void sendNotification(List<HandlerNotifier> diskList, int state, String alert)
  {
    for (HandlerNotifier dirElem : diskList)
    {
      String dirPath = dirElem.directory.getAbsolutePath();
      String handlerNames = dirElem.diskNames.toString();
      long freeSpace = dirElem.directory.getFreeSpace();
      if (state == FULL)
      {
        DirectoryServer.sendAlertNotification(this, alert,
            ERR_DISK_SPACE_FULL_THRESHOLD_REACHED.get(dirPath, handlerNames, freeSpace));
      }
      else if (state == LOW)
      {
        DirectoryServer.sendAlertNotification(this, alert,
            ERR_DISK_SPACE_LOW_THRESHOLD_REACHED.get(dirPath, handlerNames, freeSpace));
      }
      else
      {
        logger.error(NOTE_DISK_SPACE_RESTORED.get(freeSpace, dirPath));
      }
      dirElem.notifyHandlers();
    }
  }
  /** {@inheritDoc} */
  @Override
  public void run() {
  public DN getComponentEntryDN()
  {
    try
    {
      long lastFreeSpace = directory.getUsableSpace();
      if(logger.isTraceEnabled())
      {
        logger.trace("Free space for %s: %d, " +
            "low threshold: %d, full threshold: %d, state: %d",
            directory.getPath(), lastFreeSpace, lowThreshold, fullThreshold,
            lastState);
      }
      if(lastFreeSpace < fullThreshold)
      {
        if (lastState < FULL)
        {
          if(logger.isTraceEnabled())
          {
            logger.trace("State change: %d -> %d", lastState, FULL);
          }
          lastState = FULL;
          if(handler != null)
          {
            handler.diskFullThresholdReached(this);
          }
        }
      }
      else if(lastFreeSpace < lowThreshold)
      {
        if (lastState < LOW)
        {
          if(logger.isTraceEnabled())
          {
            logger.trace("State change: %d -> %d", lastState, LOW);
          }
          lastState = LOW;
          if(handler != null)
          {
            handler.diskLowThresholdReached(this);
          }
        }
      }
      else if (lastState != NORMAL)
      {
        if(logger.isTraceEnabled())
        {
          logger.trace("State change: %d -> %d", lastState, NORMAL);
        }
        lastState = NORMAL;
        if(handler != null)
        {
          handler.diskSpaceRestored(this);
        }
      }
      return DN.valueOf(INSTANCENAME);
    }
    catch(Exception e)
    catch (DirectoryException de)
    {
      logger.error(ERR_DISK_SPACE_MONITOR_UPDATE_FAILED, directory.getPath(), e);
      logger.traceException(e);
      return DN.NULL_DN;
    }
  }
  /** {@inheritDoc} */
  @Override
  public String getClassName()
  {
    return DiskSpaceMonitor.class.getName();
  }
  /** {@inheritDoc} */
  @Override
  public Map<String, String> getAlerts()
  {
    Map<String, String> alerts = new LinkedHashMap<String, String>();
    alerts.put(ALERT_TYPE_DISK_SPACE_LOW, ALERT_DESCRIPTION_DISK_SPACE_LOW);
    alerts.put(ALERT_TYPE_DISK_FULL, ALERT_DESCRIPTION_DISK_FULL);
    return alerts;
  }
  /** {@inheritDoc} */
  @Override
  public String getShutdownListenerName()
  {
    return INSTANCENAME;
  }
  /** {@inheritDoc} */
  @Override
  public void processServerShutdown(LocalizableMessage reason)
  {
    synchronized (monitoredDirs)
    {
      for (Entry<File, List<MonitoredDirectory>> dirElem : monitoredDirs.entrySet())
      {
        for (MonitoredDirectory handlerElem : dirElem.getValue())
        {
          DirectoryServer.deregisterMonitorProvider(handlerElem);
        }
      }
    }
    DirectoryServer.deregisterMonitorProvider(this);
  }
}
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
@@ -36,15 +36,20 @@
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import static org.opends.messages.UtilityMessages.*;
@@ -108,8 +113,29 @@
    /** Constructors for each of the above classes. */
    private static Constructor<?> certKeyGenCons, X500NameCons;
    /** Filesystem APIs */
    private static Method FILESYSTEMS_GETSTORES;
    private static Method FILESYSTEMS_PATHSGET;
    private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
    static
    {
      try
      {
        // FileSystem and FileStores APIs were introduced in JDK 7.
        FILESYSTEMS_PATHSGET = Class.forName("java.nio.file.Paths").getMethod("get", String.class, String[].class);
        FILESYSTEMS_GETSTORES = Class.forName("java.nio.file.Files").getMethod(
            "getFileStore", Class.forName("java.nio.file.Path"));
      }
      catch (Exception e)
      {
        FILESYSTEMS_GETSTORES = null;
        FILESYSTEMS_PATHSGET = null;
        logger.warn(WARN_UNABLE_TO_USE_FILESYSTEM_API.get());
      }
      String x509pkg = pkgPrefix + ".x509";
      String certAndKeyGen;
      if (pkgPrefix.equals(IBM_SEC)
@@ -155,21 +181,7 @@
    /**
     * Delete the specified alias from the specified keystore.
     *
     * @param ks
     *          The keystore to delete the alias from.
     * @param ksPath
     *          The path to the keystore.
     * @param alias
     *          The alias to use in the request generation.
     * @param pwd
     *          The keystore password to use.
     * @throws KeyStoreException
     *           If an error occurred deleting the alias.
     */
    public final void deleteAlias(KeyStore ks, String ksPath, String alias,
    private final void deleteAlias(KeyStore ks, String ksPath, String alias,
        char[] pwd) throws KeyStoreException
    {
      try
@@ -193,28 +205,7 @@
    /**
     * Add the certificate in the specified path to the specified keystore,
     * creating the keystore using the specified type and path if it the
     * keystore doesn't exist.
     *
     * @param ks
     *          The keystore to add the certificate to, may be null if it
     *          doesn't exist.
     * @param ksType
     *          The type to use if the keystore is created.
     * @param ksPath
     *          The path to the keystore if it is created.
     * @param alias
     *          The alias to store the certificate under.
     * @param pwd
     *          The password to use in saving the certificate.
     * @param certPath
     *          The path to the file containing the certificate.
     * @throws KeyStoreException
     *           If an error occurred adding the certificate to the keystore.
     */
    public final void addCertificate(KeyStore ks, String ksType, String ksPath,
    private final void addCertificate(KeyStore ks, String ksType, String ksPath,
        String alias, char[] pwd, String certPath) throws KeyStoreException
    {
      try
@@ -255,31 +246,7 @@
    /**
     * Generate a self-signed certificate using the specified alias, dn string
     * and validity period. If the keystore does not exist, create it using the
     * specified type and path.
     *
     * @param ks
     *          The keystore to save the certificate in. May be null if it does
     *          not exist.
     * @param ksType
     *          The keystore type to use if the keystore is created.
     * @param ksPath
     *          The path to the keystore if the keystore is created.
     * @param alias
     *          The alias to store the certificate under.
     * @param pwd
     *          The password to us in saving the certificate.
     * @param dn
     *          The dn string used as the certificate subject.
     * @param validity
     *          The validity of the certificate in days.
     * @return The keystore that the self-signed certificate was stored in.
     * @throws KeyStoreException
     *           If the self-signed certificate cannot be generated.
     */
    public final KeyStore generateSelfSignedCertificate(KeyStore ks,
    private final KeyStore generateSelfSignedCertificate(KeyStore ks,
        String ksType, String ksPath, String alias, char[] pwd, String dn,
        int validity) throws KeyStoreException
    {
@@ -330,19 +297,6 @@
    /**
     * Generate a x509 certificate from the input stream. Verification is done
     * only if it is self-signed.
     *
     * @param alias
     *          The alias to save the certificate under.
     * @param cf
     *          The x509 certificate factory.
     * @param ks
     *          The keystore to add the certificate in.
     * @param in
     *          The input stream to read the certificate from.
     * @throws KeyStoreException
     *           If the alias exists already in the keystore, if the self-signed
     *           certificate didn't verify, or the certificate could not be
     *           stored.
     */
    private void trustedCert(String alias, CertificateFactory cf, KeyStore ks,
        InputStream in) throws KeyStoreException
@@ -369,10 +323,6 @@
    /**
     * Check that the issuer and subject DNs match.
     *
     * @param cert
     *          The certificate to examine.
     * @return {@code true} if the certificate is self-signed.
     */
    private boolean isSelfSigned(X509Certificate cert)
    {
@@ -391,14 +341,7 @@
    /**
     * Calculates the usable memory which could potentially be used by the
     * application for caching objects.
     *
     * @return The usable memory which could potentially be used by the
     *         application for caching objects.
     */
    public long getUsableMemoryForCaching()
    private long getUsableMemoryForCaching()
    {
      long youngGenSize = 0;
      long oldGenSize = 0;
@@ -454,6 +397,40 @@
            .totalMemory())) * 40 / 100;
      }
    }
    private File getFilesystem(File directory) throws IOException
    {
      if (FILESYSTEMS_GETSTORES != null)
      {
        try
        {
          Object dirFStore = FILESYSTEMS_GETSTORES.invoke(null,
              FILESYSTEMS_PATHSGET.invoke(null, directory.getAbsolutePath(), new String[0]));
          File parentDir = directory.getParentFile();
          /*
           * Since there is no concept of mount point in the APIs, iterate on all parents of
           * the given directory until the FileSystem Store changes (hint of a different
           * device, hence a mount point) or we get to root, which works too.
           */
          while (parentDir != null)
          {
            Object parentFStore = FILESYSTEMS_GETSTORES.invoke(null,
                FILESYSTEMS_PATHSGET.invoke(null, parentDir.getAbsolutePath(), new String[0]));
            if (!parentFStore.equals(dirFStore))
            {
              return directory;
            }
            directory = directory.getParentFile();
            parentDir = directory.getParentFile();
          }
        }
        catch (Exception e)
        {
          throw new IOException(e);
        }
      }
      return directory;
    }
  }
@@ -648,4 +625,16 @@
  {
    return IMPL.getUsableMemoryForCaching();
  }
  /**
   * Returns the filesystem on which the given directory resides by its mountpoint.
   *
   * @param directory the directory whose filesystem is required
   * @return the filesystem on which the given directory resides
   * @throws IOException The exception in case information on filesystem/storage cannot be found
   */
  public static File getFilesystem(File directory) throws IOException
  {
    return IMPL.getFilesystem(directory);
  }
}
opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/backend.properties
@@ -1028,4 +1028,10 @@
 %d%% available
ERR_VLV_BAD_ASSERTION_430=Unable to process the virtual list view request \
 because the target assertion could not be decoded as a valid value for the \
 '%s' attribute type
 '%s' attribute type
WARN_DISK_SPACE_LOW_THRESHOLD_CROSSED_431=Disk free space of %d bytes for directory %s is now below low threshold of \
 %d bytes. Backend %s is now locked down and will no longer accept any operations from clients until sufficient disk \
 space is restored
WARN_DISK_SPACE_FULL_THRESHOLD_CROSSED_432=Disk free space of %d bytes for directory %s is now below disk low \
 threshold of %d bytes. Backend %s is now offline and will no longer accept any operations until sufficient \
 disk space is restored
opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/core.properties
@@ -1429,4 +1429,12 @@
ERR_PWPOLICY_REJECT_DUE_TO_UNKNOWN_VALIDATOR_LOG_747=The password for \
 user %s could not be validated because the password policy subentry %s is \
 referring to an unknown password validator (%s). Please make sure the password \
 policy subentry only refers to validators that exist on all replicas
 policy subentry only refers to validators that exist on all replicas
ERR_DISK_SPACE_GET_MOUNT_POINT_748=Could not get filesystem for directory %s: %s
ERR_DISK_SPACE_LOW_THRESHOLD_REACHED_749=The disk containing directory %s used by %s is low on free space \
 (%d bytes free). Write operations are only permitted by a user with the BYPASS_LOCKDOWN privilege until the free \
 space rises above the threshold. Replication updates are still allowed
ERR_DISK_SPACE_FULL_THRESHOLD_REACHED_750=The disk containing directory %s used by %s is full (%d bytes free). \
 Write operations to the backend, replication updates included, will fail until the free space rises above the threshold
NOTE_DISK_SPACE_RESTORED_751=The free space (%d bytes) on the disk containing directory %s is now above the \
 threshold
opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/jeb.properties
@@ -374,14 +374,14 @@
 perform import phase 2 in a single batch. Some indexes will be imported using \
 several batches which may result in reduced performance
ERR_IMPORT_LDIF_LACK_DISK_PHASE_ONE_222=The disk containing directory \
 %s is full (%d bytes free). After freeing more than %d bytes on the disk, \
 %s is full. After freeing more than %d bytes on the disk, \
 import can continue in append and replace mode to load the rest of the \
 entries
ERR_IMPORT_LDIF_LACK_DISK_PHASE_TWO_223=The disk containing directory \
 %s is full (%d bytes free). After freeing more than %d bytes on the disk, \
 %s is full. After freeing more than %d bytes on the disk, \
 a rebuild of all the indexes is needed to complete the import
ERR_REBUILD_INDEX_LACK_DISK_224=The disk containing directory \
 %s is full (%d bytes free). Rebuild index can not continue until the free \
 %s is full. Rebuild index can not continue until the free \
 space rises above the threshold (%d bytes)
INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED_225=%s index type is disabled for \
 the %s attribute
opendj-sdk/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
@@ -571,4 +571,5 @@
was received when reading its attributes: %s
ERR_LDAP_CONN_BAD_INTEGER_302=Invalid integer number "%s". Please \
 enter a valid integer
ERR_ARG_SUBCOMMAND_INVALID_303=Invalid subcommand
ERR_ARG_SUBCOMMAND_INVALID_303=Invalid subcommand
WARN_UNABLE_TO_USE_FILESYSTEM_API_304=Unable to gather information on Filesystem APIs, disk monitoring will be verbose
opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java
@@ -47,6 +47,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.MemoryQuota;
import org.opends.server.core.ServerContext;
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.testng.annotations.AfterMethod;
@@ -76,6 +77,7 @@
    ServerContext serverContext = mock(ServerContext.class);
    when(serverContext.getMemoryQuota()).thenReturn(new MemoryQuota());
    when(serverContext.getDiskSpaceMonitor()).thenReturn(new DiskSpaceMonitor());
    storage = new PersistItStorage(createBackendCfg(), serverContext);
    org.opends.server.backends.pluggable.spi.Importer importer = storage.startImport();