From 7ccaa46b4a749896b2daabda390d8ddd3ae7743f Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Fri, 10 Apr 2015 14:55:54 +0000
Subject: [PATCH]
---
opendj-server-legacy/src/messages/org/opends/messages/backend.properties | 8
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java | 2
opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/Importer.java | 96 ++--
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java | 13
opendj-server-legacy/src/main/java/org/opends/server/extensions/DiskSpaceMonitor.java | 585 ++++++++++++++++++++----------
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java | 52 --
opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/BackendImpl.java | 65 +--
opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java | 10
opendj-server-legacy/src/main/java/org/opends/server/api/DiskSpaceMonitorHandler.java | 23
opendj-server-legacy/src/messages/org/opends/messages/core.properties | 10
opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java | 163 ++++----
opendj-server-legacy/src/messages/org/opends/messages/utility.properties | 3
opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java | 99 +---
opendj-server-legacy/src/messages/org/opends/messages/jeb.properties | 6
14 files changed, 625 insertions(+), 510 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/DiskSpaceMonitorHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/api/DiskSpaceMonitorHandler.java
index 637879d..97de7e8 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/api/DiskSpaceMonitorHandler.java
+++ b/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);
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/BackendImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/BackendImpl.java
index 639081b..a517e4e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/BackendImpl.java
+++ b/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)))
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/Importer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/Importer.java
index 1053bed..90868d3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/Importer.java
+++ b/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.
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java
index 8076ff5..98bc297 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java
+++ b/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();
}
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java
index 41bec03..4e984da 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java
+++ b/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.
- }
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
index 9a0b462..937f721 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/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.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
index 5756c7a..a27dde7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
+++ b/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();
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/DiskSpaceMonitor.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/DiskSpaceMonitor.java
index 5a88036..90ac02a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/DiskSpaceMonitor.java
+++ b/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);
+ }
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java b/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
index be9bc43..abe7988 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
+++ b/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);
+ }
}
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/backend.properties b/opendj-server-legacy/src/messages/org/opends/messages/backend.properties
index 2f717b5..3c4f0fb 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/backend.properties
+++ b/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
\ No newline at end of file
+ '%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
\ No newline at end of file
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/core.properties b/opendj-server-legacy/src/messages/org/opends/messages/core.properties
index 5833a7d..eb040a0 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/core.properties
+++ b/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
\ No newline at end of file
+ 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
\ No newline at end of file
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/jeb.properties b/opendj-server-legacy/src/messages/org/opends/messages/jeb.properties
index 120ba89..7850b7e 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/jeb.properties
+++ b/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
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/utility.properties b/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
index 23f191a..b814f59 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
+++ b/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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java
index 93b0e75..f97d9a7 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java
+++ b/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();
--
Gitblit v1.10.0