/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/nasutekds/resource/legal-notices/NasuTekDS.LICENSE
* or https://NasuTekDS.dev.java.net/NasuTekDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/nasutekds/resource/legal-notices/NasuTekDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
*/
package org.nasutekds.server.backends.jeb;
import org.nasutekds.messages.Message;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.config.ConfigParam;
import com.sleepycat.je.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.*;
import java.io.File;
import java.io.FilenameFilter;
import org.nasutekds.server.monitors.DatabaseEnvironmentMonitor;
import org.nasutekds.server.types.DebugLogLevel;
import org.nasutekds.server.types.DN;
import org.nasutekds.server.types.FilePermission;
import org.nasutekds.server.types.ConfigChangeResult;
import org.nasutekds.server.types.ResultCode;
import org.nasutekds.server.api.Backend;
import org.nasutekds.server.admin.std.server.LocalDBBackendCfg;
import org.nasutekds.server.admin.server.ConfigurationChangeListener;
import org.nasutekds.server.core.DirectoryServer;
import org.nasutekds.server.config.ConfigException;
import static org.nasutekds.server.loggers.ErrorLogger.logError;
import static org.nasutekds.server.loggers.debug.DebugLogger.*;
import org.nasutekds.server.loggers.debug.DebugTracer;
import org.nasutekds.server.types.InitializationException;
import static org.nasutekds.messages.JebMessages.*;
import static org.nasutekds.server.util.StaticUtils.*;
import static org.nasutekds.messages.ConfigMessages.*;
/**
* Wrapper class for the JE environment. Root container holds all the entry
* containers for each base DN. It also maintains all the openings and closings
* of the entry containers.
*/
public class RootContainer
implements ConfigurationChangeListener<LocalDBBackendCfg>
{
/**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
/**
* The JE database environment.
*/
private Environment env;
//Used to force a checkpoint during import.
private CheckpointConfig importForceCheckPoint = new CheckpointConfig();
/**
* The backend configuration.
*/
private LocalDBBackendCfg config;
/**
* The backend to which this entry root container belongs.
*/
private Backend backend;
/**
* The database environment monitor for this JE environment.
*/
private DatabaseEnvironmentMonitor monitor;
/**
* The base DNs contained in this entryContainer.
*/
private ConcurrentHashMap<DN, EntryContainer> entryContainers;
/**
* The cached value of the next entry identifier to be assigned.
*/
private AtomicLong nextid = new AtomicLong(1);
/**
* The compressed schema manager for this backend.
*/
private JECompressedSchema compressedSchema;
/**
* Creates a new RootContainer object. Each root container represents a JE
* environment.
*
* @param config The configuration of the JE backend.
* @param backend A reference to the JE back end that is creating this
* root container.
*/
public RootContainer(Backend backend, LocalDBBackendCfg config)
{
this.env = null;
this.monitor = null;
this.entryContainers = new ConcurrentHashMap<DN, EntryContainer>();
this.backend = backend;
this.config = config;
this.compressedSchema = null;
getMonitorProvider().enableFilterUseStats(
config.isIndexFilterAnalyzerEnabled());
getMonitorProvider().setMaxEntries(config.getMaxEntries());
config.addLocalDBChangeListener(this);
importForceCheckPoint.setForce(true);
}
/**
* Opens the root container using the JE configuration object provided.
*
* @param envConfig The JE environment configuration.
* @throws DatabaseException If a database error occurs when creating
* the environment.
* @throws InitializationException If an initialization error occurs while
* creating the enviornment.
* @throws ConfigException If an configuration error occurs while
* creating the enviornment.
*/
public void open(EnvironmentConfig envConfig)
throws DatabaseException, InitializationException, ConfigException
{
// Determine the backend database directory.
File parentDirectory = getFileForPath(config.getDBDirectory());
File backendDirectory = new File(parentDirectory, config.getBackendId());
// Create the directory if it doesn't exist.
if (!backendDirectory.exists())
{
if(!backendDirectory.mkdirs())
{
Message message =
ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath());
throw new ConfigException(message);
}
}
//Make sure the directory is valid.
else if (!backendDirectory.isDirectory())
{
Message message =
ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath());
throw new ConfigException(message);
}
FilePermission backendPermission;
try
{
backendPermission =
FilePermission.decodeUNIXMode(config.getDBDirectoryPermissions());
}
catch(Exception e)
{
Message message =
ERR_CONFIG_BACKEND_MODE_INVALID.get(config.dn().toString());
throw new ConfigException(message);
}
//Make sure the mode will allow the server itself access to
//the database
if(!backendPermission.isOwnerWritable() ||
!backendPermission.isOwnerReadable() ||
!backendPermission.isOwnerExecutable())
{
Message message = ERR_CONFIG_BACKEND_INSANE_MODE.get(
config.getDBDirectoryPermissions());
throw new ConfigException(message);
}
// Get the backend database backendDirectory permissions and apply
if(FilePermission.canSetPermissions())
{
try
{
if(!FilePermission.setPermissions(backendDirectory, backendPermission))
{
Message message = WARN_JEB_UNABLE_SET_PERMISSIONS.get(
backendPermission.toString(), backendDirectory.toString());
logError(message);
}
}
catch(Exception e)
{
// Log an warning that the permissions were not set.
Message message = WARN_JEB_SET_PERMISSIONS_FAILED.get(
backendDirectory.toString(), e.toString());
logError(message);
}
}
// Open the database environment
env = new Environment(backendDirectory,
envConfig);
if (debugEnabled())
{
TRACER.debugInfo("JE (%s) environment opened with the following " +
"config: %n%s", JEVersion.CURRENT_VERSION.toString(),
env.getConfig().toString());
// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();
// Get maximum size of heap in bytes. The heap cannot grow beyond this
// size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();
// Get amount of free memory within the heap in bytes. This size will
// increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();
TRACER.debugInfo("Current size of heap: %d bytes", heapSize);
TRACER.debugInfo("Max size of heap: %d bytes", heapMaxSize);
TRACER.debugInfo("Free memory in heap: %d bytes", heapFreeSize);
}
compressedSchema = new JECompressedSchema(env);
openAndRegisterEntryContainers(config.getBaseDN());
}
/**
* Opens the entry container for a base DN. If the entry container does not
* exist for the base DN, it will be created. The entry container will be
* opened with the same mode as the root container. Any entry containers
* opened in a read only root container will also be read only. Any entry
* containers opened in a non transactional root container will also be non
* transactional.
*
* @param baseDN The base DN of the entry container to open.
* @param name The name of the entry container or <CODE>NULL</CODE> to open
* the default entry container for the given base DN.
* @return The opened entry container.
* @throws DatabaseException If an error occurs while opening the entry
* container.
* @throws ConfigException If an configuration error occurs while opening
* the entry container.
*/
public EntryContainer openEntryContainer(DN baseDN, String name)
throws DatabaseException, ConfigException
{
String databasePrefix;
if(name == null || name.equals(""))
{
databasePrefix = baseDN.toNormalizedString();
}
else
{
databasePrefix = name;
}
EntryContainer ec = new EntryContainer(baseDN, databasePrefix,
backend, config, env, this);
ec.open();
return ec;
}
/**
* Registeres the entry container for a base DN.
*
* @param baseDN The base DN of the entry container to close.
* @param entryContainer The entry container to register for the baseDN.
* @throws InitializationException If an error occurs while opening the
* entry container.
*/
public void registerEntryContainer(DN baseDN,
EntryContainer entryContainer)
throws InitializationException
{
EntryContainer ec1 = this.entryContainers.get(baseDN);
// If an entry container for this baseDN is already open we don't allow
// another to be opened.
if (ec1 != null)
{
Message m = ERR_JEB_ENTRY_CONTAINER_ALREADY_REGISTERED.get(
ec1.getDatabasePrefix(), baseDN.toString());
throw new InitializationException(m);
}
this.entryContainers.put(baseDN, entryContainer);
}
/**
* Opens the entry containers for multiple base DNs.
*
* @param baseDNs The base DNs of the entry containers to open.
* @throws DatabaseException If a database error occurs while opening
* the entry container.
* @throws InitializationException If an initialization error occurs while
* opening the entry container.
* @throws ConfigException If a configuration error occurs while
* opening the entry container.
*/
private void openAndRegisterEntryContainers(Set<DN> baseDNs)
throws DatabaseException, InitializationException, ConfigException
{
EntryID id;
EntryID highestID = null;
for(DN baseDN : baseDNs)
{
EntryContainer ec = openEntryContainer(baseDN, null);
id = ec.getHighestEntryID();
registerEntryContainer(baseDN, ec);
if(highestID == null || id.compareTo(highestID) > 0)
{
highestID = id;
}
}
nextid = new AtomicLong(highestID.longValue() + 1);
}
/**
* Unregisteres the entry container for a base DN.
*
* @param baseDN The base DN of the entry container to close.
* @return The entry container that was unregistered or NULL if a entry
* container for the base DN was not registered.
*/
public EntryContainer unregisterEntryContainer(DN baseDN)
{
return entryContainers.remove(baseDN);
}
/**
* Retrieves the compressed schema manager for this backend.
*
* @return The compressed schema manager for this backend.
*/
public JECompressedSchema getCompressedSchema()
{
return compressedSchema;
}
/**
* Get the DatabaseEnvironmentMonitor object for JE environment used by this
* root container.
*
* @return The DatabaseEnvironmentMonito object.
*/
public DatabaseEnvironmentMonitor getMonitorProvider()
{
if(monitor == null)
{
String monitorName = backend.getBackendID() + " Database Environment";
monitor = new DatabaseEnvironmentMonitor(monitorName, this);
}
return monitor;
}
/**
* Preload the database cache. There is no preload if the configured preload
* time limit is zero.
*
* @param timeLimit The time limit for the preload process.
*/
public void preload(long timeLimit)
{
if (timeLimit > 0)
{
// Get a list of all the databases used by the backend.
ArrayList<DatabaseContainer> dbList =
new ArrayList<DatabaseContainer>();
for (EntryContainer ec : entryContainers.values())
{
ec.sharedLock.lock();
try
{
ec.listDatabases(dbList);
}
finally
{
ec.sharedLock.unlock();
}
}
// Sort the list in order of priority.
Collections.sort(dbList, new DbPreloadComparator());
// Preload each database until we reach the time limit or the cache
// is filled.
try
{
// Configure preload of Leaf Nodes (LNs) containing the data values.
PreloadConfig preloadConfig = new PreloadConfig();
preloadConfig.setLoadLNs(true);
Message message =
NOTE_JEB_CACHE_PRELOAD_STARTED.get(backend.getBackendID());
logError(message);
boolean isInterrupted = false;
long timeEnd = System.currentTimeMillis() + timeLimit;
for (DatabaseContainer db : dbList)
{
// Calculate the remaining time.
long timeRemaining = timeEnd - System.currentTimeMillis();
if (timeRemaining <= 0)
{
break;
}
preloadConfig.setMaxMillisecs(timeRemaining);
PreloadStats preloadStats = db.preload(preloadConfig);
if(debugEnabled())
{
TRACER.debugInfo("file=" + db.getName() +
" LNs=" + preloadStats.getNLNsLoaded());
}
// Stop if the cache is full or the time limit has been exceeded.
PreloadStatus preloadStatus = preloadStats.getStatus();
if (preloadStatus != PreloadStatus.SUCCESS)
{
if (preloadStatus == PreloadStatus.EXCEEDED_TIME) {
message =
NOTE_JEB_CACHE_PRELOAD_INTERRUPTED_BY_TIME.get(
backend.getBackendID(), db.getName());
logError(message);
} else if (preloadStatus == PreloadStatus.FILLED_CACHE) {
message =
NOTE_JEB_CACHE_PRELOAD_INTERRUPTED_BY_SIZE.get(
backend.getBackendID(), db.getName());
logError(message);
} else {
message =
NOTE_JEB_CACHE_PRELOAD_INTERRUPTED_UNKNOWN.get(
backend.getBackendID(), db.getName());
logError(message);
}
isInterrupted = true;
break;
}
message = NOTE_JEB_CACHE_DB_PRELOADED.get(db.getName());
logError(message);
}
if (!isInterrupted) {
message = NOTE_JEB_CACHE_PRELOAD_DONE.get(backend.getBackendID());
logError(message);
}
// Log an informational message about the size of the cache.
EnvironmentStats stats = env.getStats(new StatsConfig());
long total = stats.getCacheTotalBytes();
message =
NOTE_JEB_CACHE_SIZE_AFTER_PRELOAD.get(total / (1024 * 1024));
logError(message);
}
catch (DatabaseException e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
Message message =
ERR_JEB_CACHE_PRELOAD.get(backend.getBackendID(),
(e.getCause() != null ? e.getCause().getMessage() :
stackTraceToSingleLineString(e)));
logError(message);
}
}
}
/**
* Synchronously invokes the cleaner on the database environment then forces a
* checkpoint to delete the log files that are no longer in use.
*
* @throws DatabaseException If an error occurs while cleaning the database
* environment.
*/
private void cleanDatabase()
throws DatabaseException
{
Message message;
FilenameFilter filenameFilter = new FilenameFilter()
{
public boolean accept(File d, String name)
{
return name.endsWith(".jdb");
}
};
File backendDirectory = env.getHome();
int beforeLogfileCount = backendDirectory.list(filenameFilter).length;
message = NOTE_JEB_CLEAN_DATABASE_START.get(
beforeLogfileCount, backendDirectory.getPath());
logError(message);
int currentCleaned = 0;
int totalCleaned = 0;
while ((currentCleaned = env.cleanLog()) > 0)
{
totalCleaned += currentCleaned;
}
message = NOTE_JEB_CLEAN_DATABASE_MARKED.get(totalCleaned);
logError(message);
if (totalCleaned > 0)
{
CheckpointConfig force = new CheckpointConfig();
force.setForce(true);
env.checkpoint(force);
}
int afterLogfileCount = backendDirectory.list(filenameFilter).length;
message = NOTE_JEB_CLEAN_DATABASE_FINISH.get(afterLogfileCount);
logError(message);
}
/**
* Close the root entryContainer.
*
* @throws DatabaseException If an error occurs while attempting to close
* the entryContainer.
*/
public void close() throws DatabaseException
{
for(DN baseDN : entryContainers.keySet())
{
EntryContainer ec = unregisterEntryContainer(baseDN);
ec.exclusiveLock.lock();
try
{
ec.close();
}
finally
{
ec.exclusiveLock.unlock();
}
}
compressedSchema.close();
config.removeLocalDBChangeListener(this);
if (env != null)
{
env.close();
env = null;
}
}
/**
* Return all the entry containers in this root container.
*
* @return The entry containers in this root container.
*/
public Collection<EntryContainer> getEntryContainers()
{
return entryContainers.values();
}
/**
* Returns all the baseDNs this root container stores.
*
* @return The set of DNs this root container stores.
*/
public Set<DN> getBaseDNs()
{
return entryContainers.keySet();
}
/**
* Return the entry container for a specific base DN.
*
* @param baseDN The base DN of the entry container to retrive.
* @return The entry container for the base DN.
*/
public EntryContainer getEntryContainer(DN baseDN)
{
EntryContainer ec = null;
DN nodeDN = baseDN;
while (ec == null && nodeDN != null)
{
ec = entryContainers.get(nodeDN);
if (ec == null)
{
nodeDN = nodeDN.getParentDNInSuffix();
}
}
return ec;
}
/**
* Get the environment stats of the JE environment used in this root
* container.
*
* @param statsConfig The configuration to use for the EnvironmentStats
* object.
* @return The environment status of the JE environment.
* @throws DatabaseException If an error occurs while retriving the stats
* object.
*/
public EnvironmentStats getEnvironmentStats(StatsConfig statsConfig)
throws DatabaseException
{
return env.getStats(statsConfig);
}
/**
* Get the environment transaction stats of the JE environment used
* in this root container.
*
* @param statsConfig The configuration to use for the EnvironmentStats
* object.
* @return The environment status of the JE environment.
* @throws DatabaseException If an error occurs while retriving the stats
* object.
*/
public TransactionStats getEnvironmentTransactionStats(
StatsConfig statsConfig) throws DatabaseException
{
return env.getTransactionStats(statsConfig);
}
/**
* Get the environment config of the JE environment used in this root
* container.
*
* @return The environment config of the JE environment.
* @throws DatabaseException If an error occurs while retriving the
* configuration object.
*/
public EnvironmentConfig getEnvironmentConfig() throws DatabaseException
{
return env.getConfig();
}
/**
* Get the backend configuration used by this root container.
*
* @return The JE backend configuration used by this root container.
*/
public LocalDBBackendCfg getConfiguration()
{
return config;
}
/**
* Get the total number of entries in this root container.
*
* @return The number of entries in this root container
* @throws DatabaseException If an error occurs while retriving the entry
* count.
*/
public long getEntryCount() throws DatabaseException
{
long entryCount = 0;
for(EntryContainer ec : this.entryContainers.values())
{
ec.sharedLock.lock();
try
{
entryCount += ec.getEntryCount();
}
finally
{
ec.sharedLock.unlock();
}
}
return entryCount;
}
/**
* Assign the next entry ID.
*
* @return The assigned entry ID.
*/
public EntryID getNextEntryID()
{
return new EntryID(nextid.getAndIncrement());
}
/**
* Return the lowest entry ID assigned.
*
* @return The lowest entry ID assigned.
*/
public Long getLowestEntryID()
{
return 1L;
}
/**
* Return the highest entry ID assigned.
*
* @return The highest entry ID assigned.
*/
public Long getHighestEntryID()
{
return (nextid.get() - 1);
}
/**
* Resets the next entry ID counter to zero. This should only be used after
* clearing all databases.
*/
public void resetNextEntryID()
{
nextid.set(1);
}
/**
* {@inheritDoc}
*/
public boolean isConfigurationChangeAcceptable(
LocalDBBackendCfg cfg,
List<Message> unacceptableReasons)
{
boolean acceptable = true;
File parentDirectory = getFileForPath(config.getDBDirectory());
File backendDirectory = new File(parentDirectory, config.getBackendId());
//Make sure the directory either already exists or is able to create.
if (!backendDirectory.exists())
{
if(!backendDirectory.mkdirs())
{
Message message =
ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath());
unacceptableReasons.add(message);
acceptable = false;
}
else
{
backendDirectory.delete();
}
}
//Make sure the directory is valid.
else if (!backendDirectory.isDirectory())
{
Message message =
ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath());
unacceptableReasons.add(message);
acceptable = false;
}
try
{
FilePermission newBackendPermission =
FilePermission.decodeUNIXMode(cfg.getDBDirectoryPermissions());
//Make sure the mode will allow the server itself access to
//the database
if(!newBackendPermission.isOwnerWritable() ||
!newBackendPermission.isOwnerReadable() ||
!newBackendPermission.isOwnerExecutable())
{
Message message = ERR_CONFIG_BACKEND_INSANE_MODE.get(
cfg.getDBDirectoryPermissions());
unacceptableReasons.add(message);
acceptable = false;
}
}
catch(Exception e)
{
Message message =
ERR_CONFIG_BACKEND_MODE_INVALID.get(cfg.dn().toString());
unacceptableReasons.add(message);
acceptable = false;
}
try
{
ConfigurableEnvironment.parseConfigEntry(cfg);
}
catch (Exception e)
{
unacceptableReasons.add(Message.raw(e.getLocalizedMessage()));
acceptable = false;
}
return acceptable;
}
/**
* {@inheritDoc}
*/
public ConfigChangeResult applyConfigurationChange(LocalDBBackendCfg cfg)
{
ConfigChangeResult ccr;
boolean adminActionRequired = false;
ArrayList<Message> messages = new ArrayList<Message>();
try
{
if(env != null)
{
// Check if any JE non-mutable properties were changed.
EnvironmentConfig oldEnvConfig = env.getConfig();
EnvironmentConfig newEnvConfig =
ConfigurableEnvironment.parseConfigEntry(cfg);
Map<?,?> paramsMap = EnvironmentParams.SUPPORTED_PARAMS;
// Iterate through native JE properties.
SortedSet<String> jeProperties = cfg.getJEProperty();
for (String jeEntry : jeProperties) {
// There is no need to validate properties yet again.
StringTokenizer st = new StringTokenizer(jeEntry, "=");
if (st.countTokens() == 2) {
String jePropertyName = st.nextToken();
String jePropertyValue = st.nextToken();
ConfigParam param = (ConfigParam) paramsMap.get(jePropertyName);
if (!param.isMutable()) {
String oldValue = oldEnvConfig.getConfigParam(param.getName());
String newValue = jePropertyValue;
if (!oldValue.equalsIgnoreCase(newValue)) {
adminActionRequired = true;
messages.add(INFO_CONFIG_JE_PROPERTY_REQUIRES_RESTART.get(
jePropertyName));
if(debugEnabled()) {
TRACER.debugInfo("The change to the following property " +
"will take effect when the component is restarted: " +
jePropertyName);
}
}
}
}
}
// Iterate through JE configuration attributes.
for (Object o : paramsMap.values())
{
ConfigParam param = (ConfigParam) o;
if (!param.isMutable())
{
String oldValue = oldEnvConfig.getConfigParam(param.getName());
String newValue = newEnvConfig.getConfigParam(param.getName());
if (!oldValue.equalsIgnoreCase(newValue))
{
adminActionRequired = true;
String configAttr = ConfigurableEnvironment.
getAttributeForProperty(param.getName());
if (configAttr != null)
{
messages.add(NOTE_JEB_CONFIG_ATTR_REQUIRES_RESTART
.get(configAttr));
}
else
{
messages.add(NOTE_JEB_CONFIG_ATTR_REQUIRES_RESTART
.get(param.getName()));
}
if(debugEnabled())
{
TRACER.debugInfo("The change to the following property will " +
"take effect when the backend is restarted: " +
param.getName());
}
}
}
}
// This takes care of changes to the JE environment for those
// properties that are mutable at runtime.
env.setMutableConfig(newEnvConfig);
if (debugEnabled())
{
TRACER.debugInfo(env.getConfig().toString());
}
}
// Create the directory if it doesn't exist.
if(!cfg.getDBDirectory().equals(this.config.getDBDirectory()))
{
File parentDirectory = getFileForPath(cfg.getDBDirectory());
File backendDirectory =
new File(parentDirectory, cfg.getBackendId());
if (!backendDirectory.exists())
{
if(!backendDirectory.mkdirs())
{
messages.add(ERR_JEB_CREATE_FAIL.get(
backendDirectory.getPath()));
ccr = new ConfigChangeResult(
DirectoryServer.getServerErrorResultCode(),
adminActionRequired,
messages);
return ccr;
}
}
//Make sure the directory is valid.
else if (!backendDirectory.isDirectory())
{
messages.add(ERR_JEB_DIRECTORY_INVALID.get(
backendDirectory.getPath()));
ccr = new ConfigChangeResult(
DirectoryServer.getServerErrorResultCode(),
adminActionRequired,
messages);
return ccr;
}
adminActionRequired = true;
messages.add(NOTE_JEB_CONFIG_DB_DIR_REQUIRES_RESTART.get(
this.config.getDBDirectory(), cfg.getDBDirectory()));
}
if(!cfg.getDBDirectoryPermissions().equalsIgnoreCase(
config.getDBDirectoryPermissions()) ||
!cfg.getDBDirectory().equals(this.config.getDBDirectory()))
{
FilePermission backendPermission;
try
{
backendPermission =
FilePermission.decodeUNIXMode(cfg.getDBDirectoryPermissions());
}
catch(Exception e)
{
messages.add(ERR_CONFIG_BACKEND_MODE_INVALID.get(
config.dn().toString()));
ccr = new ConfigChangeResult(
DirectoryServer.getServerErrorResultCode(),
adminActionRequired,
messages);
return ccr;
}
//Make sure the mode will allow the server itself access to
//the database
if(!backendPermission.isOwnerWritable() ||
!backendPermission.isOwnerReadable() ||
!backendPermission.isOwnerExecutable())
{
messages.add(ERR_CONFIG_BACKEND_INSANE_MODE.get(
cfg.getDBDirectoryPermissions()));
ccr = new ConfigChangeResult(
DirectoryServer.getServerErrorResultCode(),
adminActionRequired,
messages);
return ccr;
}
// Get the backend database backendDirectory permissions and apply
if(FilePermission.canSetPermissions())
{
File parentDirectory = getFileForPath(config.getDBDirectory());
File backendDirectory = new File(parentDirectory,
config.getBackendId());
try
{
if(!FilePermission.setPermissions(backendDirectory,
backendPermission))
{
Message message = WARN_JEB_UNABLE_SET_PERMISSIONS.get(
backendPermission.toString(), backendDirectory.toString());
logError(message);
}
}
catch(Exception e)
{
// Log an warning that the permissions were not set.
Message message = WARN_JEB_SET_PERMISSIONS_FAILED.get(
backendDirectory.toString(), e.toString());
logError(message);
}
}
}
getMonitorProvider().enableFilterUseStats(
cfg.isIndexFilterAnalyzerEnabled());
getMonitorProvider().setMaxEntries(cfg.getMaxEntries());
this.config = cfg;
}
catch (Exception e)
{
messages.add(Message.raw(stackTraceToSingleLineString(e)));
ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
adminActionRequired,
messages);
return ccr;
}
ccr = new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
messages);
return ccr;
}
/**
* Force a checkpoint.
*
* @throws DatabaseException If a database error occurs.
*/
public void importForceCheckPoint() throws DatabaseException {
env.checkpoint(importForceCheckPoint);
}
/**
* Run the cleaner and return the number of files cleaned.
*
* @return The number of logs cleaned.
* @throws DatabaseException If a database error occurs.
*/
public int cleanedLogFiles() throws DatabaseException {
int cleaned, totalCleaned = 0;
while((cleaned = env.cleanLog()) > 0) {
totalCleaned += cleaned;
}
return totalCleaned;
}
/**
* Returns whether this container JE database environment is
* open, valid and can be used.
*
* @return {@code true} if valid, or {@code false} otherwise.
*/
public boolean isValid() {
return env.isValid();
}
}