From a743f8cd823be717769cb97ad294b521a6ac8042 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 17 Dec 2014 22:59:42 +0000
Subject: [PATCH] OPENDJ-1602 (CR-5566) New pluggable storage based backend
---
/dev/null | 726 ------------------------------------------
opendj-sdk/opendj3-server-dev/resource/config/config.ldif | 9
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java | 57 ---
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java | 25
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java | 43 --
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/DefaultEntryCacheTestCase.java | 59 ---
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/BackendImpl.java | 53 ---
7 files changed, 12 insertions(+), 960 deletions(-)
diff --git a/opendj-sdk/opendj3-server-dev/resource/config/config.ldif b/opendj-sdk/opendj3-server-dev/resource/config/config.ldif
index dcabd11..c2d3f4dc 100644
--- a/opendj-sdk/opendj3-server-dev/resource/config/config.ldif
+++ b/opendj-sdk/opendj3-server-dev/resource/config/config.ldif
@@ -557,15 +557,6 @@
ds-cfg-cache-level: 2
ds-cfg-java-class: org.opends.server.extensions.SoftReferenceEntryCache
-dn: cn=File System,cn=Entry Caches,cn=config
-objectClass: top
-objectClass: ds-cfg-entry-cache
-objectClass: ds-cfg-file-system-entry-cache
-cn: File System
-ds-cfg-enabled: false
-ds-cfg-cache-level: 3
-ds-cfg-java-class: org.opends.server.extensions.FileSystemEntryCache
-
dn: cn=Extended Operations,cn=config
objectClass: top
objectClass: ds-cfg-branch
diff --git a/opendj-sdk/opendj3-server-dev/src/admin/defn/org/opends/server/admin/std/FileSystemEntryCacheConfiguration.xml b/opendj-sdk/opendj3-server-dev/src/admin/defn/org/opends/server/admin/std/FileSystemEntryCacheConfiguration.xml
deleted file mode 100644
index 13de250..0000000
--- a/opendj-sdk/opendj3-server-dev/src/admin/defn/org/opends/server/admin/std/FileSystemEntryCacheConfiguration.xml
+++ /dev/null
@@ -1,303 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ! 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 legal-notices/CDDLv1_0.txt
- ! or http://forgerock.org/license/CDDLv1.0.html.
- ! 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 legal-notices/CDDLv1_0.txt.
- ! 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 2007-2008 Sun Microsystems, Inc.
- ! Portions Copyright 2011 ForgeRock AS
- ! -->
-<adm:managed-object name="file-system-entry-cache"
- plural-name="file-system-entry-caches"
- package="org.opends.server.admin.std" extends="entry-cache"
- xmlns:adm="http://www.opends.org/admin"
- xmlns:ldap="http://www.opends.org/admin-ldap">
- <adm:synopsis>
- The
- <adm:user-friendly-name />
- is an entry cache implementation which uses a JE database to keep
- track of the entries.
- </adm:synopsis>
- <adm:description>
- For best performance, the JE database should reside in a memory
- based file system although any file system will do for this cache
- to function. Entries are maintained either by FIFO (default) or LRU-based
- (configurable) list implementation. Cache sizing is based on
- the size of free space available in the file system, such that if
- enough memory is free, then adding an entry to the cache will not
- require purging. If more than the specified size of the file
- system available space is already consumed, then one or more entries
- need to be removed in order to make room for a new entry. It is
- also possible to configure a maximum number of entries for the cache.
- If this is specified, then the number of entries are not allowed
- to exceed this value, but it may not be possible to hold this many
- entries if the available memory fills up first. Other configurable
- parameters for this cache include the maximum length of time to block
- while waiting to acquire a lock, and a set of filters that may be
- used to define criteria for determining which entries are stored in
- the cache. If a set of filters are provided then an entry must match
- at least one of them in order to be stored in the cache.
- JE environment cache size can also be configured either as a percentage
- of the free memory available in the JVM, or as an absolute size in
- bytes. This cache has a persistence property which, if enabled,
- allows for the contents of the cache to persist across server or
- cache restarts.
- </adm:description>
- <adm:profile name="ldap">
- <ldap:object-class>
- <ldap:name>ds-cfg-file-system-entry-cache</ldap:name>
- <ldap:superior>ds-cfg-entry-cache</ldap:superior>
- </ldap:object-class>
- </adm:profile>
- <adm:property name="lock-timeout" advanced="true">
- <adm:synopsis>
- The length of time to wait while attempting to acquire a read or
- write lock.
- </adm:synopsis>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>2000.0ms</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:duration base-unit="ms" allow-unlimited="true" />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-lock-timeout</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="max-memory-size">
- <adm:synopsis>
- The maximum size of the entry cache in bytes.
- </adm:synopsis>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>0b</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:size />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-max-memory-size</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="max-entries">
- <adm:synopsis>
- The maximum number of entries allowed in the cache.
- </adm:synopsis>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>2147483647</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:integer lower-limit="0" />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-max-entries</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="cache-type">
- <adm:synopsis>
- Specifies the policy which should be used for purging entries from
- the cache.
- </adm:synopsis>
- <adm:requires-admin-action>
- <adm:component-restart />
- </adm:requires-admin-action>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>fifo</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:enumeration>
- <adm:value name="fifo">
- <adm:synopsis>FIFO based entry cache.</adm:synopsis>
- </adm:value>
- <adm:value name="lru">
- <adm:synopsis>LRU based entry cache.</adm:synopsis>
- </adm:value>
- </adm:enumeration>
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-cache-type</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="cache-directory">
- <adm:synopsis>
- Specifies the directory in which the JE environment should store
- the cache.
- </adm:synopsis>
- <adm:requires-admin-action>
- <adm:component-restart />
- </adm:requires-admin-action>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>/tmp/OpenDJ.FSCache</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:string />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-cache-directory</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="persistent-cache">
- <adm:synopsis>
- Specifies whether the cache should persist across restarts.
- </adm:synopsis>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>false</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:boolean />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-persistent-cache</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="compact-encoding">
- <adm:synopsis>
- Indicates whether the cache should use a compact form when
- encoding cache entries by compressing the attribute descriptions
- and object class sets.
- </adm:synopsis>
- <adm:description>
- Note that compression does not preserve user-supplied
- capitalization in the object class and attribute type names.
- </adm:description>
- <adm:requires-admin-action>
- <adm:none>
- <adm:synopsis>
- Changing this property only affects the encoding of the
- cache entries put in the cache after the change is made. It
- will not be retroactively applied to existing cache entries.
- </adm:synopsis>
- </adm:none>
- </adm:requires-admin-action>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>true</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:boolean />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-compact-encoding</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="db-cache-percent">
- <adm:synopsis>
- Specifies the maximum memory usage for the internal JE cache as a percentage
- of the total JVM memory.
- </adm:synopsis>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>1</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:integer lower-limit="0" upper-limit="90" />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-db-cache-percent</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="db-cache-size">
- <adm:synopsis>
- Specifies the maximum JVM memory usage in bytes for the internal JE cache.
- </adm:synopsis>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>0b</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:size />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-db-cache-size</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property name="je-property" multi-valued="true"
- advanced="true">
- <adm:synopsis>
- Specifies the environment properties for the Berkeley DB Java
- Edition database providing the backend for this entry cache.
- </adm:synopsis>
- <adm:description>
- Any Berkeley DB Java Edition property can be specified using the
- following form: property-name=property-value. Refer to the
- <adm:product-name /> documentation for further information on related
- properties, their implications and range values. The definitive
- identification of all the property parameters available in the
- example.properties file in the Berkeley DB Java Edition distribution.
- </adm:description>
- <adm:default-behavior>
- <adm:defined>
- <adm:value>je.env.isLocking=false</adm:value>
- </adm:defined>
- </adm:default-behavior>
- <adm:syntax>
- <adm:string />
- </adm:syntax>
- <adm:profile name="ldap">
- <ldap:attribute>
- <ldap:name>ds-cfg-je-property</ldap:name>
- </ldap:attribute>
- </adm:profile>
- </adm:property>
- <adm:property-reference name="include-filter" />
- <adm:property-reference name="exclude-filter" />
- <adm:property-override name="java-class" advanced="true">
- <adm:default-behavior>
- <adm:defined>
- <adm:value>
- org.opends.server.extensions.FileSystemEntryCache
- </adm:value>
- </adm:defined>
- </adm:default-behavior>
- </adm:property-override>
-</adm:managed-object>
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/BackendImpl.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/BackendImpl.java
index 556d614..544ae50 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/BackendImpl.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/BackendImpl.java
@@ -27,16 +27,12 @@
package org.opends.server.backends.jeb;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
-import java.util.zip.Adler32;
-import java.util.zip.CheckedInputStream;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -153,50 +149,6 @@
}
}
- /**
- * This method will attempt to checksum the current JE db environment by
- * computing the Adler-32 checksum on the latest JE log file available.
- *
- * @return The checksum of JE db environment or zero if checksum failed.
- */
- private long checksumDbEnv() {
-
- File parentDirectory = getFileForPath(cfg.getDBDirectory());
- File backendDirectory = new File(parentDirectory, cfg.getBackendId());
-
- List<File> jdbFiles = new ArrayList<File>();
- if(backendDirectory.isDirectory())
- {
- jdbFiles =
- Arrays.asList(backendDirectory.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".jdb");
- }
- }));
- }
-
- if ( !jdbFiles.isEmpty() ) {
- Collections.sort(jdbFiles, Collections.reverseOrder());
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(jdbFiles.get(0).toString());
- CheckedInputStream cis = new CheckedInputStream(fis, new Adler32());
- byte[] tempBuf = new byte[8192];
- while (cis.read(tempBuf) >= 0) {
- }
-
- return cis.getChecksum().getValue();
- } catch (Exception e) {
- logger.traceException(e);
- } finally {
- close(fis);
- }
- }
-
- return 0;
- }
-
/** {@inheritDoc} */
@Override
public void configureBackend(LocalDBBackendCfg cfg) throws ConfigException
@@ -212,9 +164,6 @@
public void initializeBackend()
throws ConfigException, InitializationException
{
- // Checksum this db environment and register its offline state id/checksum.
- DirectoryServer.registerOfflineBackendStateID(getBackendID(), checksumDbEnv());
-
if (mustOpenRootContainer())
{
rootContainer = initializeRootContainer(parseConfigEntry(cfg));
@@ -310,8 +259,6 @@
logger.error(ERR_JEB_DATABASE_EXCEPTION, e.getMessage());
}
- // Checksum this db environment and register its offline state id/checksum.
- DirectoryServer.registerOfflineBackendStateID(getBackendID(), checksumDbEnv());
DirectoryServer.deregisterAlertGenerator(this);
// Make sure the thread counts are zero for next initialization.
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java
index 585d715..1a54c7c 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/BackendImpl.java
@@ -27,15 +27,11 @@
package org.opends.server.backends.pluggable;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
-import java.util.zip.Adler32;
-import java.util.zip.CheckedInputStream;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -67,8 +63,8 @@
* This is an implementation of a Directory Server Backend which stores entries
* locally in a Berkeley DB JE database.
*/
-public class BackendImpl extends Backend<LocalDBBackendCfg>
- implements ConfigurationChangeListener<LocalDBBackendCfg>, AlertGenerator,
+public class BackendImpl extends Backend<LocalDBBackendCfg> implements
+ ConfigurationChangeListener<LocalDBBackendCfg>, AlertGenerator,
DiskSpaceMonitorHandler
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
@@ -130,50 +126,6 @@
}
}
- /**
- * This method will attempt to checksum the current JE db environment by
- * computing the Adler-32 checksum on the latest JE log file available.
- *
- * @return The checksum of JE db environment or zero if checksum failed.
- */
- private long checksumDbEnv() {
-
- File parentDirectory = getFileForPath(cfg.getDBDirectory());
- File backendDirectory = new File(parentDirectory, cfg.getBackendId());
-
- List<File> jdbFiles = new ArrayList<File>();
- if(backendDirectory.isDirectory())
- {
- jdbFiles =
- Arrays.asList(backendDirectory.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".jdb");
- }
- }));
- }
-
- if ( !jdbFiles.isEmpty() ) {
- Collections.sort(jdbFiles, Collections.reverseOrder());
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(jdbFiles.get(0).toString());
- CheckedInputStream cis = new CheckedInputStream(fis, new Adler32());
- byte[] tempBuf = new byte[8192];
- while (cis.read(tempBuf) >= 0) {
- }
-
- return cis.getChecksum().getValue();
- } catch (Exception e) {
- logger.traceException(e);
- } finally {
- close(fis);
- }
- }
-
- return 0;
- }
-
/** {@inheritDoc} */
@Override
public void configureBackend(LocalDBBackendCfg cfg) throws ConfigException
@@ -189,9 +141,6 @@
public void initializeBackend()
throws ConfigException, InitializationException
{
- // Checksum this db environment and register its offline state id/checksum.
- DirectoryServer.registerOfflineBackendStateID(getBackendID(), checksumDbEnv());
-
if (mustOpenRootContainer())
{
rootContainer = initializeRootContainer();
@@ -285,8 +234,6 @@
logger.error(ERR_JEB_DATABASE_EXCEPTION, e.getMessage());
}
- // Checksum this db environment and register its offline state id/checksum.
- DirectoryServer.registerOfflineBackendStateID(getBackendID(), checksumDbEnv());
DirectoryServer.deregisterAlertGenerator(this);
// Make sure the thread counts are zero for next initialization.
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java
index 4daaa84..7588f22 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java
@@ -775,13 +775,6 @@
/** The set of backends registered with the server. */
private TreeMap<String, Backend<?>> backends;
- /**
- * The mapping between backends and their unique identifiers for their offline
- * state, representing either checksum or other unique value to be used for
- * detecting any offline modifications to a given backend.
- */
- private ConcurrentMap<String, Long> offlineBackendsStateIDs;
-
/** The set of supported controls registered with the Directory Server. */
private final TreeSet<String> supportedControls = new TreeSet<String>(Arrays.asList(
OID_LDAP_ASSERTION,
@@ -1088,8 +1081,6 @@
new ConcurrentHashMap<String,
MonitorProvider<? extends MonitorProviderCfg>>();
directoryServer.backends = new TreeMap<String, Backend<?>>();
- directoryServer.offlineBackendsStateIDs =
- new ConcurrentHashMap<String,Long>();
directoryServer.backendInitializationListeners =
new CopyOnWriteArraySet<BackendInitializationListener>();
directoryServer.baseDnRegistry = new BaseDnRegistry();
@@ -1555,9 +1546,6 @@
// If not then stick with default entry cache initialized earlier.
entryCacheConfigManager.initializeEntryCache();
- // Reset the map as we can no longer guarantee offline state.
- directoryServer.offlineBackendsStateIDs.clear();
-
initializeExtendedOperations();
initializeSASLMechanisms();
@@ -5191,37 +5179,6 @@
/**
- * This method returns a map that contains a unique offline state id,
- * such as checksum, for every server backend that has registered one.
- *
- * @return <CODE>Map</CODE> backend to checksum map for offline state.
- */
- public static Map<String,Long> getOfflineBackendsStateIDs() {
- return Collections.unmodifiableMap(directoryServer.offlineBackendsStateIDs);
- }
-
-
-
- /**
- * This method allows any server backend to register its unique offline
- * state, such as checksum, in a global map other server components can
- * access to determine if any changes were made to given backend while
- * offline.
- *
- * @param backend As returned by <CODE>getBackendID()</CODE> method.
- *
- * @param id Unique offline state identifier such as checksum.
- */
- public static void registerOfflineBackendStateID(String backend, long id) {
- // Zero means failed checksum so just skip it.
- if (id != 0) {
- directoryServer.offlineBackendsStateIDs.put(backend, id);
- }
- }
-
-
-
- /**
* Retrieves the entire set of base DNs registered with the Directory Server,
* mapped from the base DN to the backend responsible for that base DN. The
* same backend may be present multiple times, mapped from different base DNs.
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/FileSystemEntryCache.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/FileSystemEntryCache.java
deleted file mode 100644
index 41be44e..0000000
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/FileSystemEntryCache.java
+++ /dev/null
@@ -1,1539 +0,0 @@
-/*
- * 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 legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * 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 legal-notices/CDDLv1_0.txt.
- * 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 2008 Sun Microsystems, Inc.
- * Portions Copyright 2011-2014 ForgeRock AS
- */
-package org.opends.server.extensions;
-
-import java.io.File;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import com.sleepycat.bind.EntryBinding;
-import com.sleepycat.bind.serial.SerialBinding;
-import com.sleepycat.bind.serial.StoredClassCatalog;
-import com.sleepycat.je.Environment;
-import com.sleepycat.je.EnvironmentConfig;
-import com.sleepycat.je.EnvironmentMutableConfig;
-import com.sleepycat.je.Database;
-import com.sleepycat.je.DatabaseConfig;
-import com.sleepycat.je.DatabaseEntry;
-import com.sleepycat.je.DatabaseNotFoundException;
-import com.sleepycat.je.LockMode;
-import com.sleepycat.je.OperationStatus;
-import com.sleepycat.je.StatsConfig;
-import com.sleepycat.je.config.ConfigParam;
-import com.sleepycat.je.config.EnvironmentParams;
-
-import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ByteStringBuilder;
-import org.forgerock.util.Utils;
-import org.opends.server.admin.server.ConfigurationChangeListener;
-import org.opends.server.admin.server.ServerManagementContext;
-import org.opends.server.admin.std.server.EntryCacheCfg;
-import org.opends.server.admin.std.server.FileSystemEntryCacheCfg;
-import org.opends.server.admin.std.server.RootCfg;
-import org.opends.server.api.Backend;
-import org.opends.server.api.EntryCache;
-import org.opends.server.backends.jeb.ConfigurableEnvironment;
-import org.forgerock.opendj.config.server.ConfigException;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.opends.server.util.ServerConstants;
-
-import static org.opends.messages.ConfigMessages.*;
-import static org.opends.messages.ExtensionMessages.*;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-/**
- * This class defines a Directory Server entry cache that uses JE database to
- * keep track of the entries. Intended use is when JE database resides in the
- * memory based file system which has obvious performance benefits, although
- * any file system will do for this cache to function. Entries are maintained
- * either by FIFO (default) or LRU (configurable) based list implementation.
- * <BR><BR>
- * Cache sizing is based on the size of free space available in the file
- * system, such that if enough memory is free, then adding an entry to the
- * cache will not require purging, but if more than a specified size of the
- * file system available space is already consumed, then one or more entries
- * will need to be removed in order to make room for a new entry. It is also
- * possible to configure a maximum number of entries for the cache. If this
- * is specified, then the number of entries will not be allowed to exceed
- * this value, but it may not be possible to hold this many entries if the
- * available memory fills up first.
- * <BR><BR>
- * Other configurable parameters for this cache include the maximum length of
- * time to block while waiting to acquire a lock, and a set of filters that may
- * be used to define criteria for determining which entries are stored in the
- * cache. If a filter list is provided, then only entries matching at least
- * one of the given filters will be stored in the cache.
- * <BR><BR>
- * JE environment cache size can also be configured either as percentage of
- * the free memory available in the JVM or as explicit size in bytes.
- * <BR><BR>
- * This cache has a persistence property which, if enabled, allows for the
- * contents of the cache to stay persistent across server or cache restarts.
- */
-public class FileSystemEntryCache
- extends EntryCache <FileSystemEntryCacheCfg>
- implements ConfigurationChangeListener <FileSystemEntryCacheCfg> {
- private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
-
- // Permissions for cache db environment.
- private static final FilePermission CACHE_HOME_PERMISSIONS =
- new FilePermission(0700);
-
- // The maximum amount of space in bytes that can be consumed in the filesystem
- // before we need to start purging entries.
- private long maxAllowedMemory;
-
- // The maximum number of entries that may be held in the cache.
- // Atomic for additional safety and in case we decide to push
- // some locks further down later. Does not inhere in additional
- // overhead, via blocking on synchronization primitive, on most
- // modern platforms being implemented via cpu instruction set.
- private AtomicLong maxEntries;
-
- // The entry cache home folder to host db environment.
- private String cacheHome;
-
- // The type of this cache.
- // It can be either FIFO (default) or LRU (configurable).
- private String cacheType;
-
- // This regulates whether we persist the cache across restarts or not.
- private boolean persistentCache;
-
- // The lock used to provide threadsafe access when changing the contents
- // of the cache maps.
- private ReentrantReadWriteLock cacheLock;
- private Lock cacheReadLock;
- private Lock cacheWriteLock;
-
- // Entry Cache Index.
- FileSystemEntryCacheIndex entryCacheIndex;
-
- // Access order for this cache. FIFO by default.
- boolean accessOrder = false;
-
- // JE environment and database related fields for this cache.
- private Environment entryCacheEnv;
- private EnvironmentConfig entryCacheEnvConfig;
- private EnvironmentMutableConfig entryCacheEnvMutableConfig;
- private DatabaseConfig entryCacheDBConfig;
-
- // Statistics retrieval operation config for this JE environment.
- private StatsConfig entryCacheEnvStatsConfig = new StatsConfig();
-
- // The main entry cache database.
- private Database entryCacheDB;
-
- // Class database, catalog and binding for serialization.
- private Database entryCacheClassDB;
- private StoredClassCatalog classCatalog;
- private EntryBinding<FileSystemEntryCacheIndex> entryCacheDataBinding;
-
- // JE naming constants.
- private static final String ENTRYCACHEDBNAME = "EntryCacheDB";
- private static final String INDEXCLASSDBNAME = "IndexClassDB";
- private static final String INDEXKEY = "EntryCacheIndex";
-
- // The configuration to use when encoding entries in the database.
- private EntryEncodeConfig encodeConfig =
- new EntryEncodeConfig(true, true, true);
-
- // JE native properties to configuration attributes map.
- private HashMap<String, String> configAttrMap =
- new HashMap<String, String>();
-
- // Currently registered configuration object.
- private FileSystemEntryCacheCfg registeredConfiguration;
-
- // The maximum length of time to try to obtain a lock before giving
- // up.
- private long lockTimeout = LockManager.DEFAULT_TIMEOUT;
-
- /**
- * Creates a new instance of this entry cache.
- */
- public FileSystemEntryCache() {
- super();
-
- // Register all JE native properties that map to
- // corresponding config attributes.
- configAttrMap.put("je.maxMemoryPercent",
- ConfigurableEnvironment.ATTR_DATABASE_CACHE_PERCENT);
- configAttrMap.put("je.maxMemory",
- ConfigurableEnvironment.ATTR_DATABASE_CACHE_SIZE);
-
- // All initialization should be performed in the initializeEntryCache.
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void initializeEntryCache(FileSystemEntryCacheCfg configuration)
- throws ConfigException, InitializationException {
-
- registeredConfiguration = configuration;
- configuration.addFileSystemChangeListener (this);
-
- // Read and apply configuration.
- boolean applyChanges = true;
- ArrayList<LocalizableMessage> errorMessages = new ArrayList<LocalizableMessage>();
- EntryCacheCommon.ConfigErrorHandler errorHandler =
- EntryCacheCommon.getConfigErrorHandler (
- EntryCacheCommon.ConfigPhase.PHASE_INIT, null, errorMessages
- );
- if (!processEntryCacheConfig(configuration, applyChanges, errorHandler)) {
- String buffer = Utils.joinAsString(". ", errorMessages);
- throw new ConfigException(ERR_FSCACHE_CANNOT_INITIALIZE.get(buffer));
- }
-
- // Set the cache type.
- if (cacheType.equalsIgnoreCase("LRU")) {
- accessOrder = true;
- } else {
- // Admin framework should only allow for either FIFO or LRU but
- // we set the type to default here explicitly if it is not LRU.
- cacheType = DEFAULT_FSCACHE_TYPE;
- accessOrder = false;
- }
-
- // Initialize the index.
- entryCacheIndex = new FileSystemEntryCacheIndex(this, accessOrder);
-
- // Initialize locks.
- cacheLock = new ReentrantReadWriteLock(true);
- if (accessOrder) {
- // In access-ordered linked hash maps, merely querying the map
- // with get() is a structural modification.
- cacheReadLock = cacheLock.writeLock();
- } else {
- cacheReadLock = cacheLock.readLock();
- }
- cacheWriteLock = cacheLock.writeLock();
-
- // Setup the cache home.
- try {
- checkAndSetupCacheHome(cacheHome);
- } catch (Exception e) {
- logger.traceException(e);
-
- // Not having any home directory for the cache db environment is a
- // fatal error as we are unable to continue any further without it.
- LocalizableMessage message =
- ERR_FSCACHE_HOMELESS.get();
- throw new InitializationException(message, e);
- }
-
- // Configure and open JE environment and cache database.
- try {
- entryCacheEnvConfig.setAllowCreate(true);
- entryCacheEnv = new Environment(new File(cacheHome), entryCacheEnvConfig);
- entryCacheEnv.setMutableConfig(entryCacheEnvMutableConfig);
- entryCacheDBConfig = new DatabaseConfig();
- entryCacheDBConfig.setAllowCreate(true);
-
- // Configure the JE environment statistics to return only
- // the values which do not incur some performance penalty.
- entryCacheEnvStatsConfig.setFast(true);
-
- // Remove old cache databases if this cache is not persistent.
- if ( !persistentCache ) {
- try {
- entryCacheEnv.removeDatabase(null, INDEXCLASSDBNAME);
- } catch (DatabaseNotFoundException e) {}
- try {
- entryCacheEnv.removeDatabase(null, ENTRYCACHEDBNAME);
- } catch (DatabaseNotFoundException e) {}
- }
-
- entryCacheDB = entryCacheEnv.openDatabase(null,
- ENTRYCACHEDBNAME, entryCacheDBConfig);
- entryCacheClassDB =
- entryCacheEnv.openDatabase(null, INDEXCLASSDBNAME, entryCacheDBConfig);
- // Instantiate the class catalog
- classCatalog = new StoredClassCatalog(entryCacheClassDB);
- //This line causes an unchecked call error if the SuppressWarnings
- //annotation is removed at the beginning of this method.
- entryCacheDataBinding = new SerialBinding<FileSystemEntryCacheIndex>(
- classCatalog, FileSystemEntryCacheIndex.class);
-
- // Get the root configuration object.
- ServerManagementContext managementContext =
- ServerManagementContext.getInstance();
- RootCfg rootConfiguration =
- managementContext.getRootConfiguration();
-
- // Restoration is static and not subject to the current configuration
- // constraints so that the persistent state is truly preserved and
- // restored to the exact same state where we left off when the cache
- // has been made persistent. The only exception to this is the backend
- // offline state matching where entries that belong to backend which
- // we cannot match offline state for are discarded from the cache.
- if ( persistentCache &&
- // If preload is requested there is no point restoring the cache.
- !rootConfiguration.getGlobalConfiguration(
- ).isEntryCachePreload()) {
- // Retrieve cache index.
- try {
- DatabaseEntry indexData = new DatabaseEntry();
- DatabaseEntry indexKey = new DatabaseEntry(
- INDEXKEY.getBytes("UTF-8"));
-
- // Persistent state report.
- logger.info(NOTE_FSCACHE_RESTORE);
-
- if (OperationStatus.SUCCESS ==
- entryCacheDB.get(null, indexKey, indexData, LockMode.DEFAULT)) {
- entryCacheIndex = entryCacheDataBinding.entryToObject(indexData);
- } else {
- throw new CacheIndexNotFoundException();
- }
- // Check cache index state.
- if ((entryCacheIndex.dnMap.isEmpty()) ||
- (entryCacheIndex.backendMap.isEmpty()) ||
- (entryCacheIndex.offlineState.isEmpty())) {
- throw new CacheIndexImpairedException();
- } else {
- // Restore entry cache maps from this index.
-
- // Push maxEntries and make it unlimited til restoration complete.
- AtomicLong currentMaxEntries = maxEntries;
- maxEntries.set(DEFAULT_FSCACHE_MAX_ENTRIES);
-
- // Compare last known offline states to offline states on startup.
- Map<String,Long> currentBackendsState =
- DirectoryServer.getOfflineBackendsStateIDs();
- Set<String> offlineBackendSet =
- entryCacheIndex.offlineState.keySet();
- Iterator<String> offlineBackendIterator =
- offlineBackendSet.iterator();
- while (offlineBackendIterator.hasNext()) {
- String backend = offlineBackendIterator.next();
- Long offlineId = entryCacheIndex.offlineState.get(backend);
- Long currentId = currentBackendsState.get(backend);
- if ( !(offlineId.equals(currentId)) ) {
- // Remove cache entries specific to this backend.
- clearBackend(DirectoryServer.getBackend(backend));
- logger.warn(WARN_FSCACHE_OFFLINE_STATE_FAIL, backend);
- }
- }
- // Pop max entries limit.
- maxEntries = currentMaxEntries;
- }
-
- // Persistent state report.
- logger.info(NOTE_FSCACHE_RESTORE_REPORT, entryCacheIndex.dnMap.size());
-
- } catch (CacheIndexNotFoundException e) {
- logger.traceException(e);
- logger.info(NOTE_FSCACHE_INDEX_NOT_FOUND);
- clear();
- } catch (CacheIndexImpairedException e) {
- logger.traceException(e);
- logger.error(ERR_FSCACHE_INDEX_IMPAIRED);
- clear();
- } catch (Exception e) {
- logger.traceException(e);
- logger.error(ERR_FSCACHE_CANNOT_LOAD_PERSISTENT_DATA);
- clear();
- }
- }
- } catch (Exception e) {
- // If we got here it means we have failed to have a proper backend
- // for this entry cache and there is absolutely no point going any
- // farther from here.
- logger.traceException(e);
-
- LocalizableMessage message =
- ERR_FSCACHE_CANNOT_INITIALIZE.get(
- (e.getCause() != null ? e.getCause().getMessage() :
- stackTraceToSingleLineString(e)));
- throw new InitializationException(message, e);
- }
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void finalizeEntryCache() {
-
- cacheWriteLock.lock();
-
- try {
- registeredConfiguration.removeFileSystemChangeListener(this);
-
- // Store index/maps in case of persistent cache. Since the cache database
- // already exist at this point all we have to do is to serialize cache
- // index maps @see FileSystemEntryCacheIndex and put them under indexkey
- // allowing for the index to be restored and cache contents reused upon
- // the next initialization. If this cache is empty skip persisting phase.
- if (persistentCache && !entryCacheIndex.dnMap.isEmpty()) {
- // There must be at least one backend at this stage.
- entryCacheIndex.offlineState =
- DirectoryServer.getOfflineBackendsStateIDs();
-
- // Store the index.
- try {
- DatabaseEntry indexData = new DatabaseEntry();
-
- // Persistent state save report.
- logger.info(NOTE_FSCACHE_SAVE);
- //This line causes an unchecked call error if the SuppressWarnings
- //annotation is removed at the beginning of this method.
- entryCacheDataBinding.objectToEntry(entryCacheIndex, indexData);
- DatabaseEntry indexKey =
- new DatabaseEntry(INDEXKEY.getBytes("UTF-8"));
- if (OperationStatus.SUCCESS != entryCacheDB.put(null, indexKey,
- indexData)) {
- throw new Exception();
- }
- } catch (Exception e) {
- logger.traceException(e);
- logger.error(ERR_FSCACHE_CANNOT_STORE_PERSISTENT_DATA);
- }
-
- // Persistent state save report.
- logger.info(NOTE_FSCACHE_SAVE_REPORT, entryCacheIndex.dnMap.size());
- }
-
- // Close JE databases and environment and clear all the maps.
- try {
- entryCacheIndex.backendMap.clear();
- entryCacheIndex.dnMap.clear();
- if (entryCacheDB != null) {
- entryCacheDB.close();
- }
- if (entryCacheClassDB != null) {
- entryCacheClassDB.close();
- }
- if (entryCacheEnv != null) {
- // Remove cache and index dbs if this cache is not persistent.
- if (!persistentCache) {
- try {
- entryCacheEnv.removeDatabase(null, INDEXCLASSDBNAME);
- } catch (DatabaseNotFoundException e) {}
- try {
- entryCacheEnv.removeDatabase(null, ENTRYCACHEDBNAME);
- } catch (DatabaseNotFoundException e) {}
- }
- entryCacheEnv.cleanLog();
- entryCacheEnv.close();
- }
- } catch (Exception e) {
- logger.traceException(e);
-
- // That is ok, JE verification and repair on startup should take care of
- // this so if there are any unrecoverable errors during next startup
- // and we are unable to handle and cleanup them we will log errors then.
- }
- } finally {
- cacheWriteLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean containsEntry(DN entryDN)
- {
- if (entryDN == null) {
- return false;
- }
-
- // Indicate whether the DN map contains the specified DN.
- boolean containsEntry = false;
- cacheReadLock.lock();
- try {
- containsEntry = entryCacheIndex.dnMap.containsKey(
- entryDN.toNormalizedString());
- } finally {
- cacheReadLock.unlock();
- }
- return containsEntry;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Entry getEntry(DN entryDN) {
- // Get the entry from the DN map if it is present. If not, then return
- // null.
- Entry entry = null;
- cacheReadLock.lock();
- try {
- // Use get to generate entry access.
- if (entryCacheIndex.dnMap.get(entryDN.toNormalizedString()) != null) {
- entry = getEntryFromDB(entryDN);
- // Indicate cache hit.
- cacheHits.getAndIncrement();
- } else {
- // Indicate cache miss.
- cacheMisses.getAndIncrement();
- }
- } finally {
- cacheReadLock.unlock();
- }
- return entry;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long getEntryID(DN entryDN) {
- long entryID = -1;
- cacheReadLock.lock();
- try {
- Long eid = entryCacheIndex.dnMap.get(entryDN.toNormalizedString());
- if (eid != null) {
- entryID = eid.longValue();
- }
- } finally {
- cacheReadLock.unlock();
- }
- return entryID;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public DN getEntryDN(Backend backend, long entryID) {
- DN entryDN = null;
- cacheReadLock.lock();
- try {
- // Get the map for the provided backend. If it isn't present, then
- // return null.
- Map<Long, String> map = entryCacheIndex.backendMap.get(backend
- .getBackendID());
- if (map != null)
- {
- // Get the entry DN from the map by its ID. If it isn't present,
- // then return null.
- entryDN = DN.valueOf(map.get(entryID));
- }
- } catch (Exception e) {
- // Ignore.
- } finally {
- cacheReadLock.unlock();
- }
- return entryDN;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void putEntry(Entry entry, Backend backend, long entryID)
- {
- try {
- // TODO: Cache the buffer?
- ByteStringBuilder buffer = new ByteStringBuilder();
- entry.encode(buffer, encodeConfig);
- putEntryToDB(entry.getName().toNormalizedString(),
- backend, entryID, buffer);
- } catch (Exception e) {
- logger.traceException(e);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID)
- {
- cacheReadLock.lock();
- try {
- // See if the entry already exists in the cache. If it does, then we
- // will fail and not actually store the entry.
- if (entryCacheIndex.dnMap.containsKey(
- entry.getName().toNormalizedString())) {
- return false;
- }
- } finally {
- cacheReadLock.unlock();
- }
- try {
- // TODO: Cache the buffer?
- ByteStringBuilder buffer = new ByteStringBuilder();
- entry.encode(buffer, encodeConfig);
- return putEntryToDB(entry.getName().toNormalizedString(),
- backend, entryID, buffer);
- } catch (Exception e) {
- logger.traceException(e);
- // We can't rule out the possibility of a conflict, so return false.
- return false;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeEntry(DN entryDN) {
-
- cacheWriteLock.lock();
-
- try {
- Long entryID = entryCacheIndex.dnMap.get(entryDN.toNormalizedString());
- if (entryID == null) {
- return;
- }
- Set<String> backendSet = entryCacheIndex.backendMap.keySet();
- Iterator<String> backendIterator = backendSet.iterator();
- while (backendIterator.hasNext()) {
- Map<Long,String> map = entryCacheIndex.backendMap.get(
- backendIterator.next());
- if ((map.get(entryID) != null) &&
- (map.get(entryID).equals(entryDN.toNormalizedString()))) {
- map.remove(entryID);
- // If this backend becomes empty now
- // remove it from the backend map.
- if (map.isEmpty()) {
- backendIterator.remove();
- }
- break;
- }
- }
- entryCacheIndex.dnMap.remove(entryDN.toNormalizedString());
- entryCacheDB.delete(null,
- new DatabaseEntry(entryDN.toNormalizedString().getBytes("UTF-8")));
- } catch (Exception e) {
- logger.traceException(e);
- } finally {
- cacheWriteLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void clear() {
-
- cacheWriteLock.lock();
-
- try {
- entryCacheIndex.dnMap.clear();
- entryCacheIndex.backendMap.clear();
-
- try {
- if ((entryCacheDB != null) && (entryCacheEnv != null) &&
- (entryCacheClassDB != null) && (entryCacheDBConfig != null)) {
- entryCacheDBConfig = entryCacheDB.getConfig();
- entryCacheDB.close();
- entryCacheClassDB.close();
- entryCacheEnv.truncateDatabase(null, ENTRYCACHEDBNAME, false);
- entryCacheEnv.truncateDatabase(null, INDEXCLASSDBNAME, false);
- entryCacheEnv.cleanLog();
- entryCacheDB = entryCacheEnv.openDatabase(null, ENTRYCACHEDBNAME,
- entryCacheDBConfig);
- entryCacheClassDB = entryCacheEnv.openDatabase(null,
- INDEXCLASSDBNAME, entryCacheDBConfig);
- // Instantiate the class catalog
- classCatalog = new StoredClassCatalog(entryCacheClassDB);
- //This line causes an unchecked call error if the SuppressWarnings
- //annotation is removed at the beginning of this method.
- entryCacheDataBinding = new SerialBinding<FileSystemEntryCacheIndex>(
- classCatalog, FileSystemEntryCacheIndex.class);
- }
- } catch (Exception e) {
- logger.traceException(e);
- }
- } finally {
- cacheWriteLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void clearBackend(Backend backend) {
-
- cacheWriteLock.lock();
-
- try {
- Map<Long, String> backendEntriesMap =
- entryCacheIndex.backendMap.get(backend.getBackendID());
-
- try {
- if (backendEntriesMap == null) {
- // No entries were in the cache for this backend,
- // so we can return without doing anything.
- return;
- }
- int entriesExamined = 0;
- Iterator<Long> backendEntriesIterator =
- backendEntriesMap.keySet().iterator();
- while (backendEntriesIterator.hasNext()) {
- Long entryID = backendEntriesIterator.next();
- DN entryDN = DN.valueOf(backendEntriesMap.get(entryID));
- entryCacheDB.delete(null, new DatabaseEntry(
- entryDN.toNormalizedString().getBytes("UTF-8")));
- backendEntriesIterator.remove();
- entryCacheIndex.dnMap.remove(entryDN.toNormalizedString());
-
- // This can take a while, so we'll periodically release and
- // re-acquire the lock in case anyone else is waiting on it
- // so this doesn't become a stop-the-world event as far as
- // the cache is concerned.
- entriesExamined++;
- if ((entriesExamined % 1000) == 0) {
- cacheWriteLock.unlock();
- Thread.yield();
- cacheWriteLock.lock();
- }
- }
-
- // This backend is empty now, remove it from the backend map.
- entryCacheIndex.backendMap.remove(backend.getBackendID());
- } catch (Exception e) {
- logger.traceException(e);
- }
- } finally {
- cacheWriteLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void clearSubtree(DN baseDN) {
- // Determine which backend should be used for the provided base DN. If
- // there is none, then we don't need to do anything.
- Backend backend = DirectoryServer.getBackend(baseDN);
- if (backend == null)
- {
- return;
- }
-
- // Acquire a lock on the cache. We should not return until the cache has
- // been cleared, so we will block until we can obtain the lock.
- cacheWriteLock.lock();
-
- // At this point, it is absolutely critical that we always release the lock
- // before leaving this method, so do so in a finally block.
- try
- {
- clearSubtree(baseDN, backend);
- }
- catch (Exception e)
- {
- logger.traceException(e);
- // This shouldn't happen, but there's not much that we can do if it does.
- }
- finally
- {
- cacheWriteLock.unlock();
- }
- }
-
- /**
- * Clears all entries at or below the specified base DN that are associated
- * with the given backend. The caller must already hold the cache lock.
- *
- * @param baseDN The base DN below which all entries should be flushed.
- * @param backend The backend for which to remove the appropriate entries.
- */
- private void clearSubtree(DN baseDN, Backend backend) {
- // See if there are any entries for the provided backend in the cache. If
- // not, then return.
- Map<Long,String> map =
- entryCacheIndex.backendMap.get(backend.getBackendID());
- if (map == null)
- {
- // No entries were in the cache for this backend, so we can return without
- // doing anything.
- return;
- }
-
- // Since the provided base DN could hold a subset of the information in the
- // specified backend, we will have to do this by iterating through all the
- // entries for that backend. Since this could take a while, we'll
- // periodically release and re-acquire the lock in case anyone else is
- // waiting on it so this doesn't become a stop-the-world event as far as the
- // cache is concerned.
- int entriesExamined = 0;
- Iterator<String> iterator = map.values().iterator();
- while (iterator.hasNext())
- {
- try {
- DN entryDN = DN.valueOf(iterator.next());
- if (entryDN.isDescendantOf(baseDN)) {
- iterator.remove();
- entryCacheIndex.dnMap.remove(entryDN.toNormalizedString());
- try {
- entryCacheDB.delete(null,
- new DatabaseEntry(
- entryDN.toNormalizedString().getBytes("UTF-8")));
- } catch (Exception e) {
- logger.traceException(e);
- }
- }
-
- entriesExamined++;
- if ((entriesExamined % 1000) == 0) {
- cacheWriteLock.unlock();
- Thread.yield();
- cacheWriteLock.lock();
- }
- } catch (Exception e) {
- // Ignore.
- }
- }
-
- // If this backend becomes empty now
- // remove it from the backend map.
- if (map.isEmpty()) {
- entryCacheIndex.backendMap.remove(backend.getBackendID());
- }
-
- // See if the backend has any subordinate backends. If so, then process
- // them recursively.
- for (Backend subBackend : backend.getSubordinateBackends())
- {
- boolean isAppropriate = false;
- for (DN subBase : subBackend.getBaseDNs())
- {
- if (subBase.isDescendantOf(baseDN))
- {
- isAppropriate = true;
- break;
- }
- }
-
- if (isAppropriate)
- {
- clearSubtree(baseDN, subBackend);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleLowMemory() {
- // This is about all we can do.
- if (entryCacheEnv != null) {
- try {
- // Free some JVM memory.
- entryCacheEnv.evictMemory();
- // Free some main memory/space.
- entryCacheEnv.cleanLog();
- } catch (Exception e) {
- logger.traceException(e);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public boolean isConfigurationAcceptable(EntryCacheCfg configuration,
- List<LocalizableMessage> unacceptableReasons)
- {
- FileSystemEntryCacheCfg config = (FileSystemEntryCacheCfg) configuration;
- return isConfigurationChangeAcceptable(config, unacceptableReasons);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isConfigurationChangeAcceptable(
- FileSystemEntryCacheCfg configuration,
- List<LocalizableMessage> unacceptableReasons
- )
- {
- boolean applyChanges = false;
- EntryCacheCommon.ConfigErrorHandler errorHandler =
- EntryCacheCommon.getConfigErrorHandler (
- EntryCacheCommon.ConfigPhase.PHASE_ACCEPTABLE,
- unacceptableReasons,
- null
- );
- processEntryCacheConfig (configuration, applyChanges, errorHandler);
-
- return errorHandler.getIsAcceptable();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ConfigChangeResult applyConfigurationChange(
- FileSystemEntryCacheCfg configuration
- )
- {
- boolean applyChanges = true;
- ArrayList<LocalizableMessage> errorMessages = new ArrayList<LocalizableMessage>();
- EntryCacheCommon.ConfigErrorHandler errorHandler =
- EntryCacheCommon.getConfigErrorHandler (
- EntryCacheCommon.ConfigPhase.PHASE_APPLY, null, errorMessages
- );
-
- // Do not apply changes unless this cache is enabled.
- if (configuration.isEnabled()) {
- processEntryCacheConfig (configuration, applyChanges, errorHandler);
- }
-
- boolean adminActionRequired = errorHandler.getIsAdminActionRequired();
- ConfigChangeResult changeResult = new ConfigChangeResult(
- errorHandler.getResultCode(),
- adminActionRequired,
- errorHandler.getErrorMessages()
- );
-
- return changeResult;
- }
-
- /**
- * Parses the provided configuration and configure the entry cache.
- *
- * @param configuration The new configuration containing the changes.
- * @param applyChanges If true then take into account the new configuration.
- * @param errorHandler An handler used to report errors.
- *
- * @return <CODE>true</CODE> if configuration is acceptable,
- * or <CODE>false</CODE> otherwise.
- */
- public boolean processEntryCacheConfig(
- FileSystemEntryCacheCfg configuration,
- boolean applyChanges,
- EntryCacheCommon.ConfigErrorHandler errorHandler
- )
- {
- // Local variables to read configuration.
- DN newConfigEntryDN;
- long newLockTimeout;
- long newMaxEntries;
- long newMaxAllowedMemory;
- HashSet<SearchFilter> newIncludeFilters = null;
- HashSet<SearchFilter> newExcludeFilters = null;
- int newJECachePercent;
- long newJECacheSize;
- boolean newPersistentCache;
- boolean newCompactEncoding;
- String newCacheType = DEFAULT_FSCACHE_TYPE;
- String newCacheHome = DEFAULT_FSCACHE_HOME;
- SortedSet<String> newJEProperties;
-
- EnvironmentMutableConfig newMutableEnvConfig =
- new EnvironmentMutableConfig();
- EnvironmentConfig newEnvConfig =
- new EnvironmentConfig();
-
- // Read configuration.
- newConfigEntryDN = configuration.dn();
- newLockTimeout = configuration.getLockTimeout();
-
- // If the value of zero arrives make sure it is traslated
- // to the maximum possible value we can cap maxEntries to.
- newMaxEntries = configuration.getMaxEntries();
- if (newMaxEntries <= 0) {
- newMaxEntries = DEFAULT_FSCACHE_MAX_ENTRIES;
- }
-
- // Maximum memory/space this cache can utilize.
- newMaxAllowedMemory = configuration.getMaxMemorySize();
-
- // Determine JE cache percent.
- newJECachePercent = configuration.getDBCachePercent();
-
- // Determine JE cache size.
- newJECacheSize = configuration.getDBCacheSize();
-
- // Check if this cache is persistent.
- newPersistentCache = configuration.isPersistentCache();
-
- // Check if this cache should use compact encoding.
- newCompactEncoding = configuration.isCompactEncoding();
-
- // Get native JE properties.
- newJEProperties = configuration.getJEProperty();
-
- switch (errorHandler.getConfigPhase())
- {
- case PHASE_INIT:
- // Determine the cache type.
- newCacheType = configuration.getCacheType().toString();
-
- // Determine the cache home.
- newCacheHome = configuration.getCacheDirectory();
-
- newIncludeFilters = EntryCacheCommon.getFilters(
- configuration.getIncludeFilter(),
- ERR_CACHE_INVALID_INCLUDE_FILTER,
- errorHandler,
- newConfigEntryDN
- );
- newExcludeFilters = EntryCacheCommon.getFilters (
- configuration.getExcludeFilter(),
- ERR_CACHE_INVALID_EXCLUDE_FILTER,
- errorHandler,
- newConfigEntryDN
- );
- // JE configuration properties.
- try {
- newMutableEnvConfig.setCachePercent((newJECachePercent != 0 ?
- newJECachePercent :
- EnvironmentConfig.DEFAULT.getCachePercent()));
- } catch (Exception e) {
- logger.traceException(e);
- errorHandler.reportError(
- ERR_FSCACHE_CANNOT_SET_JE_MEMORY_PCT.get(),
- false,
- DirectoryServer.getServerErrorResultCode()
- );
- }
- try {
- newMutableEnvConfig.setCacheSize(newJECacheSize);
- } catch (Exception e) {
- logger.traceException(e);
- errorHandler.reportError(
- ERR_FSCACHE_CANNOT_SET_JE_MEMORY_SIZE.get(),
- false,
- DirectoryServer.getServerErrorResultCode()
- );
- }
- // JE native properties.
- try {
- newEnvConfig = ConfigurableEnvironment.setJEProperties(
- newEnvConfig, newJEProperties, configAttrMap);
- } catch (Exception e) {
- logger.traceException(e);
- errorHandler.reportError(
- ERR_FSCACHE_CANNOT_SET_JE_PROPERTIES.get(e.getMessage()),
- false, DirectoryServer.getServerErrorResultCode());
- }
- break;
- case PHASE_ACCEPTABLE: // acceptable and apply are using the same
- case PHASE_APPLY: // error ID codes
- newIncludeFilters = EntryCacheCommon.getFilters (
- configuration.getIncludeFilter(),
- ERR_CACHE_INVALID_INCLUDE_FILTER,
- errorHandler,
- newConfigEntryDN
- );
- newExcludeFilters = EntryCacheCommon.getFilters (
- configuration.getExcludeFilter(),
- ERR_CACHE_INVALID_EXCLUDE_FILTER,
- errorHandler,
- newConfigEntryDN
- );
- // Iterate through native JE properties.
- try {
- Map<String, ConfigParam> paramsMap = EnvironmentParams.SUPPORTED_PARAMS;
- // If this entry cache is disabled then there is no open JE
- // environment to check against, skip mutable check if so.
- if (configuration.isEnabled()) {
- newMutableEnvConfig =
- ConfigurableEnvironment.setJEProperties(
- entryCacheEnv.getConfig(), newJEProperties, configAttrMap);
- EnvironmentConfig oldEnvConfig = entryCacheEnv.getConfig();
- for (String jeEntry : newJEProperties) {
- // 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 = paramsMap.get(jePropertyName);
- if (!param.isMutable()) {
- String oldValue = oldEnvConfig.getConfigParam(param.getName());
- String newValue = jePropertyValue;
- if (!oldValue.equalsIgnoreCase(newValue)) {
- LocalizableMessage message =
- INFO_CONFIG_JE_PROPERTY_REQUIRES_RESTART.get(
- jePropertyName);
- errorHandler.reportError(message, true, ResultCode.SUCCESS,
- true);
- if (logger.isTraceEnabled()) {
- logger.trace("The change to the following property " +
- "will take effect when the component is restarted: " +
- jePropertyName);
- }
- }
- }
- }
- }
- } else {
- newMutableEnvConfig =
- ConfigurableEnvironment.setJEProperties(
- new EnvironmentConfig(), newJEProperties, configAttrMap);
- }
- } catch (ConfigException ce) {
- errorHandler.reportError(ce.getMessageObject(),
- false, DirectoryServer.getServerErrorResultCode());
- } catch (Exception e) {
- errorHandler.reportError(
- LocalizableMessage.raw(stackTraceToSingleLineString(e)),
- false, DirectoryServer.getServerErrorResultCode());
- }
- break;
- }
-
- if (applyChanges && errorHandler.getIsAcceptable())
- {
- switch (errorHandler.getConfigPhase()) {
- case PHASE_INIT:
- cacheType = newCacheType;
- cacheHome = newCacheHome;
- entryCacheEnvConfig = newEnvConfig;
- entryCacheEnvMutableConfig = newMutableEnvConfig;
- break;
- case PHASE_APPLY:
- try {
- newMutableEnvConfig =
- entryCacheEnv.getMutableConfig();
- newMutableEnvConfig.setCachePercent((newJECachePercent != 0 ?
- newJECachePercent :
- EnvironmentConfig.DEFAULT.getCachePercent()));
- entryCacheEnv.setMutableConfig(newMutableEnvConfig);
- entryCacheEnv.evictMemory();
- } catch (Exception e) {
- logger.traceException(e);
- errorHandler.reportError(
- ERR_FSCACHE_CANNOT_SET_JE_MEMORY_PCT.get(),
- false,
- DirectoryServer.getServerErrorResultCode()
- );
- }
- try {
- newMutableEnvConfig =
- entryCacheEnv.getMutableConfig();
- newMutableEnvConfig.setCacheSize(newJECacheSize);
- entryCacheEnv.setMutableConfig(newMutableEnvConfig);
- entryCacheEnv.evictMemory();
- } catch (Exception e) {
- logger.traceException(e);
- errorHandler.reportError(
- ERR_FSCACHE_CANNOT_SET_JE_MEMORY_SIZE.get(),
- false,
- DirectoryServer.getServerErrorResultCode()
- );
- }
- try {
- EnvironmentConfig oldEnvConfig = entryCacheEnv.getConfig();
- newEnvConfig = ConfigurableEnvironment.setJEProperties(
- oldEnvConfig, newJEProperties, configAttrMap);
- // This takes care of changes to the JE environment for those
- // properties that are mutable at runtime.
- entryCacheEnv.setMutableConfig(newEnvConfig);
- } catch (Exception e) {
- logger.traceException(e);
- errorHandler.reportError(
- ERR_FSCACHE_CANNOT_SET_JE_PROPERTIES.get(e.getMessage()),
- false,
- DirectoryServer.getServerErrorResultCode()
- );
- }
- break;
- }
-
- maxEntries = new AtomicLong(newMaxEntries);
- maxAllowedMemory = newMaxAllowedMemory;
- persistentCache = newPersistentCache;
-
- encodeConfig = new EntryEncodeConfig(true,
- newCompactEncoding, newCompactEncoding);
-
- lockTimeout = newLockTimeout;
- setIncludeFilters(newIncludeFilters);
- setExcludeFilters(newExcludeFilters);
-
- registeredConfiguration = configuration;
- }
-
- return errorHandler.getIsAcceptable();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ArrayList<Attribute> getMonitorData()
- {
- ArrayList<Attribute> attrs = new ArrayList<Attribute>();
-
- try {
- attrs = EntryCacheCommon.getGenericMonitorData(
- new Long(cacheHits.longValue()),
- // If cache misses is maintained by default cache
- // get it from there and if not point to itself.
- DirectoryServer.getEntryCache().getCacheMisses(),
- new Long(entryCacheEnv.getStats(
- entryCacheEnvStatsConfig).getTotalLogSize()),
- new Long(maxAllowedMemory),
- new Long(entryCacheIndex.dnMap.size()),
- (((maxEntries.longValue() != Integer.MAX_VALUE) &&
- (maxEntries.longValue() != Long.MAX_VALUE)) ?
- new Long(maxEntries.longValue()) : new Long(0))
- );
- } catch (Exception e) {
- logger.traceException(e);
- }
-
- return attrs;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long getCacheCount()
- {
- return new Long(entryCacheIndex.dnMap.size());
- }
-
- /**
- * Retrieves and decodes the entry with the specified DN from JE backend db.
- *
- * @param entryDN The DN of the entry to retrieve.
- *
- * @return The requested entry if it is present in the cache, or
- * <CODE>null</CODE> if it is not present.
- */
- private Entry getEntryFromDB(DN entryDN)
- {
- DatabaseEntry cacheEntryKey = new DatabaseEntry();
- DatabaseEntry primaryData = new DatabaseEntry();
-
- try {
- // Get the primary key and data.
- cacheEntryKey.setData(entryDN.toNormalizedString().getBytes("UTF-8"));
- if (entryCacheDB.get(null, cacheEntryKey,
- primaryData,
- LockMode.DEFAULT) == OperationStatus.SUCCESS) {
-
- Entry entry = Entry.decode(
- ByteString.wrap(primaryData.getData()).asReader());
- entry.setDN(entryDN);
- return entry;
- } else {
- throw new Exception();
- }
- } catch (Exception e) {
- logger.traceException(e);
- logger.error(ERR_FSCACHE_CANNOT_RETRIEVE_ENTRY);
- }
- return null;
- }
-
- /**
- * Encodes and stores the entry in the JE backend db.
- *
- * @param backend The backend with which the entry is associated.
- * @param entryID The entry ID within the provided backend that uniquely
- * identifies the specified entry.
- *
- * @return <CODE>false</CODE> if some problem prevented the method from
- * completing successfully, or <CODE>true</CODE> if the entry
- * was either stored or the cache determined that this entry
- * should never be cached for some reason.
- */
- private boolean putEntryToDB(String dnString,
- Backend backend,
- long entryID,
- ByteStringBuilder entryBytes) {
- try {
- // Obtain a lock on the cache. If this fails, then don't do anything.
- if (!cacheWriteLock.tryLock(lockTimeout, TimeUnit.MILLISECONDS)) {
- return false;
- }
- // See if the current fs space usage is within acceptable constraints. If
- // so, then add the entry to the cache (or replace it if it is already
- // present). If not, then remove an existing entry and don't add the new
- // entry.
- // Zero means unlimited here.
- if (maxAllowedMemory != 0) {
- // Get approximate current total log size of JE environment in bytes.
- long usedMemory =
- entryCacheEnv.getStats(entryCacheEnvStatsConfig).getTotalLogSize();
-
- // TODO: Check and log a warning if usedMemory hits default or
- // configurable watermark, see Issue 1735.
-
- if (usedMemory > maxAllowedMemory) {
- long savedMaxEntries = maxEntries.longValue();
- // Cap maxEntries artificially but dont let it go negative under
- // any circumstances.
- maxEntries.set((entryCacheIndex.dnMap.isEmpty() ? 0 :
- entryCacheIndex.dnMap.size() - 1));
- // Add the entry to the map to trigger remove of the eldest entry.
- // @see LinkedHashMapRotator.removeEldestEntry() for more details.
- entryCacheIndex.dnMap.put(dnString, entryID);
- // Restore the map and maxEntries.
- entryCacheIndex.dnMap.remove(dnString);
- maxEntries.set(savedMaxEntries);
- // We'll always return true in this case, even tho we didn't actually
- // add the entry due to memory constraints.
- return true;
- }
- }
-
- // Create key.
- DatabaseEntry cacheEntryKey = new DatabaseEntry();
- cacheEntryKey.setData(dnString.getBytes("UTF-8"));
-
- // Create data and put this cache entry into the database.
- if (entryCacheDB.put(null, cacheEntryKey,
- new DatabaseEntry(entryBytes.getBackingArray(), 0,
- entryBytes.length())) == OperationStatus.SUCCESS) {
- // Add the entry to the cache index maps.
- Map<Long,String> map =
- entryCacheIndex.backendMap.get(backend.getBackendID());
- if (map == null) {
- map = new HashMap<Long,String>();
- map.put(entryID, dnString);
- entryCacheIndex.backendMap.put(backend.getBackendID(), map);
- } else {
- map.put(entryID, dnString);
- }
- entryCacheIndex.dnMap.put(dnString, entryID);
- }
-
- // We'll always return true in this case, even if we didn't actually add
- // the entry due to memory constraints.
- return true;
- } catch (Exception e) {
- logger.traceException(e);
- logger.error(ERR_FSCACHE_CANNOT_STORE_ENTRY);
- return false;
- } finally {
- if (cacheLock.isWriteLockedByCurrentThread()) {
- cacheWriteLock.unlock();
- }
- }
- }
-
- /**
- * Checks if the cache home exist and if not tries to recursively create it.
- * If either is successful adjusts cache home access permissions accordingly
- * to allow only process owner or the superuser to access JE environment.
- *
- * @param cacheHome String representation of complete file system path.
- *
- * @throws Exception If failed to establish cache home.
- */
- private void checkAndSetupCacheHome(String cacheHome) throws Exception {
-
- boolean cacheHasHome;
- File cacheHomeDir = new File(cacheHome);
- if (cacheHomeDir.exists() &&
- cacheHomeDir.canRead() &&
- cacheHomeDir.canWrite()) {
- cacheHasHome = true;
- } else {
- try {
- cacheHasHome = cacheHomeDir.mkdirs();
- } catch (SecurityException e) {
- cacheHasHome = false;
- }
- }
- if ( cacheHasHome ) {
- // TODO: Investigate if its feasible to employ SetFileAttributes()
- // FILE_ATTRIBUTE_TEMPORARY attribute on Windows via native code.
- if(FilePermission.canSetPermissions()) {
- try {
- if(!FilePermission.setPermissions(cacheHomeDir,
- CACHE_HOME_PERMISSIONS)) {
- throw new Exception();
- }
- } catch(Exception e) {
- // Log a warning that the permissions were not set.
- logger.warn(WARN_FSCACHE_SET_PERMISSIONS_FAILED, cacheHome);
- }
- }
- } else {
- throw new Exception();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public String toVerboseString()
- {
- StringBuilder sb = new StringBuilder();
-
- Map<String,Long> dnMapCopy;
- Map<String,Map<Long,String>> backendMapCopy;
-
- // Grab write lock to prevent any modifications
- // to the cache maps until a snapshot is taken.
- cacheWriteLock.lock();
- try {
- // Examining the real maps will hold the lock
- // and can cause map modifications in case of
- // any access order maps, make copies instead.
- dnMapCopy = new LinkedHashMap<String,Long>(entryCacheIndex.dnMap);
- backendMapCopy =
- new HashMap<String,Map<Long,String>>
- (entryCacheIndex.backendMap);
- } finally {
- cacheWriteLock.unlock();
- }
-
- // Check dnMap first.
- for (String dn : dnMapCopy.keySet()) {
- sb.append(dn);
- sb.append(":");
- sb.append(dnMapCopy.get(dn) != null ? dnMapCopy.get(dn) : null);
- sb.append(":");
- String backendID = null;
- Iterator<String> backendIterator = backendMapCopy.keySet().iterator();
- while (backendIterator.hasNext()) {
- backendID = backendIterator.next();
- Map<Long, String> map = backendMapCopy.get(backendID);
- if ((map != null) &&
- (map.get(dnMapCopy.get(dn)) != null) &&
- (map.get(dnMapCopy.get(dn)).equals(dn))) {
- break;
- }
- }
- sb.append(backendID);
- sb.append(ServerConstants.EOL);
- }
-
- // See if there is anything on backendMap that isnt reflected on dnMap
- // in case maps went out of sync.
- Iterator<String> backendIterator = backendMapCopy.keySet().iterator();
- while (backendIterator.hasNext()) {
- String backendID = backendIterator.next();
- Map<Long, String> map = backendMapCopy.get(backendID);
- for (Long id : map.keySet()) {
- if (!dnMapCopy.containsKey(map.get(id)) || map.get(id) == null) {
- sb.append((map.get(id) != null ? map.get(id) : null));
- sb.append(":");
- sb.append(id.toString());
- sb.append(":");
- sb.append(backendID);
- sb.append(ServerConstants.EOL);
- }
- }
- }
-
- String verboseString = sb.toString();
-
- return (verboseString.length() > 0 ? verboseString : null);
- }
-
- /**
- * This method is called each time we add a new key/value pair to the map.
- * The eldest entry is selected by the LinkedHashMap implementation based
- * on the access order configured.
- *
- * @param eldest The least recently inserted entry in the map, or if
- * this is an access-ordered map, the least recently
- * accessed entry. This is the entry that will be
- * removed it this method returns true. If the map was
- * empty prior to the put or putAll invocation resulting
- * in this invocation, this will be the entry that was
- * just inserted; in other words, if the map contains a
- * single entry, the eldest entry is also the newest.
- *
- * @return boolean {@code true} if the eldest entry should be removed
- * from the map; {@code false} if it should be retained.
- */
- protected boolean removeEldestEntry(Map.Entry<String, Long> eldest) {
- // Check if we hit the limit on max entries and if so remove
- // the eldest entry otherwise do nothing.
- if (entryCacheIndex.dnMap.size() > maxEntries.longValue()) {
- DatabaseEntry cacheEntryKey = new DatabaseEntry();
- cacheWriteLock.lock();
- try {
- // Remove the the eldest entry from supporting maps.
- String entryStringDN = eldest.getKey();
- long entryID = eldest.getValue();
- cacheEntryKey.setData(entryStringDN.getBytes("UTF-8"));
- Set<String> backendSet = entryCacheIndex.backendMap.keySet();
- Iterator<String> backendIterator = backendSet.iterator();
- while (backendIterator.hasNext()) {
- Map<Long, String> map = entryCacheIndex.backendMap.get(
- backendIterator.next());
- if ((map.get(entryID) != null) &&
- (map.get(entryID).equals(entryStringDN))) {
- map.remove(entryID);
- // If this backend becomes empty now
- // remove it from the backend map.
- if (map.isEmpty()) {
- backendIterator.remove();
- }
- break;
- }
- }
- // Remove the the eldest entry from the database.
- entryCacheDB.delete(null, cacheEntryKey);
- } catch (Exception e) {
- logger.traceException(e);
- } finally {
- cacheWriteLock.unlock();
- }
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * This exception should be thrown if an error occurs while
- * trying to locate and load persistent cache index from
- * the existing entry cache database.
- */
- private class CacheIndexNotFoundException extends OpenDsException {
- static final long serialVersionUID = 6444756053577853869L;
- public CacheIndexNotFoundException() {}
- }
-
- /**
- * This exception should be thrown if persistent cache index
- * found in the existing entry cache database is determined
- * to be empty, inconsistent or damaged.
- */
- private class CacheIndexImpairedException extends OpenDsException {
- static final long serialVersionUID = -369455697709478407L;
- public CacheIndexImpairedException() {}
- }
-
-}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/FileSystemEntryCacheIndex.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/FileSystemEntryCacheIndex.java
deleted file mode 100644
index 6335352..0000000
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/FileSystemEntryCacheIndex.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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 legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * 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 legal-notices/CDDLv1_0.txt.
- * 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 2008 Sun Microsystems, Inc.
- */
-
-package org.opends.server.extensions;
-
-import java.io.Serializable;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * This class represents serializable entry cache index structures
- * and supporting data types used for the entry cache persistence.
- * Structurally it should be an inner class of FileSystemEntryCache
- * however due to serialization constraints it has been separated.
- */
-class FileSystemEntryCacheIndex implements Serializable {
-
- static final long serialVersionUID = 4537634108673038611L;
-
- /**
- * The file system entry cache instance this index belongs to.
- */
- transient private FileSystemEntryCache fsEntryCacheInstance;
-
- /**
- * Backend to checksum/id map for offline state.
- */
- public Map<String, Long> offlineState;
- /**
- * The mapping between backends and ID to DN maps.
- */
- public Map<String, Map<Long, String>> backendMap;
- /**
- * The mapping between DNs and IDs.
- */
- public Map<String, Long> dnMap;
-
- /**
- * Index constructor.
- * @param fsEntryCacheInstance The File System Entry Cache instance
- * this index is associated with.
- * @param accessOrder The ordering mode for the index map
- * {@code true} for access-order,
- * {@code false} for insertion-order.
- */
- protected FileSystemEntryCacheIndex(
- FileSystemEntryCache fsEntryCacheInstance, boolean accessOrder) {
-
- this.fsEntryCacheInstance = fsEntryCacheInstance;
-
- offlineState =
- new ConcurrentHashMap<String, Long>();
- backendMap =
- new HashMap<String, Map<Long, String>>();
- dnMap =
- new LinkedHashMapRotator<String,Long>(
- 16, (float) 0.75, accessOrder);
- }
-
- /**
- * This inner class exist solely to override <CODE>removeEldestEntry()</CODE>
- * method of the LinkedHashMap.
- *
- * @see java.util.LinkedHashMap
- */
- private class LinkedHashMapRotator<K,V> extends LinkedHashMap<K,V> {
-
- static final long serialVersionUID = 5271482121415968435L;
-
- /**
- * Linked Hash Map Rotator constructor.
- * @param initialCapacity The initial capacity.
- * @param loadFactor The load factor.
- * @param accessOrder The ordering mode - {@code true} for
- * access-order, {@code false} for
- * insertion-order.
- */
- public LinkedHashMapRotator(int initialCapacity,
- float loadFactor,
- boolean accessOrder) {
- super(initialCapacity, loadFactor, accessOrder);
- }
-
- /**
- * This method will get called each time we add a new key/value
- * pair to the map. The eldest entry will be selected by the
- * underlying LinkedHashMap implementation based on the access
- * order configured and will follow either FIFO implementation
- * by default or LRU implementation if configured so explicitly.
- * @param eldest The least recently inserted entry in the map,
- * or if this is an access-ordered map, the least
- * recently accessed entry.
- * @return boolean {@code true} if the eldest entry should be
- * removed from the map; {@code false} if it
- * should be retained.
- */
- @Override protected boolean removeEldestEntry(Map.Entry eldest) {
- return fsEntryCacheInstance.removeEldestEntry(eldest);
- }
- }
-}
diff --git a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/DefaultEntryCacheTestCase.java b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/DefaultEntryCacheTestCase.java
index 071ca6c..8b44383 100644
--- a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/DefaultEntryCacheTestCase.java
+++ b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/DefaultEntryCacheTestCase.java
@@ -28,7 +28,6 @@
-import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.SortedMap;
@@ -38,7 +37,6 @@
import org.testng.annotations.BeforeClass;
import org.opends.server.admin.std.meta.*;
import org.opends.server.admin.std.server.EntryCacheCfg;
-import org.opends.server.admin.std.server.FileSystemEntryCacheCfg;
import org.opends.server.api.Backend;
import org.opends.server.api.EntryCache;
import org.opends.server.core.DirectoryServer;
@@ -63,12 +61,10 @@
// Entry cache implementations participating in this test.
private SoftReferenceEntryCache softRefCache = null;
private FIFOEntryCache fifoCache = null;
- private FileSystemEntryCache fsCache = null;
// ... and their configuration entries.
Entry cacheSoftReferenceConfigEntry = null;
Entry cacheFIFOConfigEntry = null;
- Entry cacheFSConfigEntry = null;
// The entry cache order map sorted by the cache level.
private SortedMap<Integer, EntryCache<? extends EntryCacheCfg>>
@@ -78,7 +74,6 @@
// Dummy test entries for each participating implementation.
private ArrayList<Entry> testSoftRefEntriesList = null;
private ArrayList<Entry> testFIFOEntriesList = null;
- private ArrayList<Entry> testFSEntriesList = null;
/**
* Initialize the entry cache test.
@@ -127,32 +122,11 @@
"ds-cfg-enabled: true",
"ds-cfg-include-filter: uid=fifo*",
"ds-cfg-include-filter: uid=test2*",
- "ds-cfg-exclude-filter: uid=test0*");
+ "ds-cfg-include-filter: uid=test0*");
fifoCache.initializeEntryCache(AdminTestCaseUtils.getConfiguration(
FIFOEntryCacheCfgDefn.getInstance(), cacheFIFOConfigEntry));
cacheOrderMap.put(2, fifoCache);
- File cacheDirectory = TestCaseUtils.createTemporaryDirectory("opendj-test");
- fsCache = new FileSystemEntryCache();
- cacheFSConfigEntry = TestCaseUtils.makeEntry(
- "dn: cn=File System,cn=Entry Caches,cn=config",
- "objectClass: ds-cfg-file-system-entry-cache",
- "objectClass: ds-cfg-entry-cache",
- "objectClass: top",
- "cn: File System",
- "ds-cfg-cache-level: 3",
- "ds-cfg-java-class: " +
- "org.opends.server.extensions.FileSystemEntryCache",
- "ds-cfg-enabled: true",
- "ds-cfg-include-filter: uid=fs*",
- "ds-cfg-include-filter: uid=test3*",
- "ds-cfg-include-filter: uid=test0*",
- "ds-cfg-cache-directory: " + cacheDirectory.getAbsolutePath());
-
- fsCache.initializeEntryCache(AdminTestCaseUtils.getConfiguration(
- FileSystemEntryCacheCfgDefn.getInstance(), cacheFSConfigEntry));
- cacheOrderMap.put(3, fsCache);
-
// Plug all cache implementations into default entry cache.
final Method[] defaultCacheMethods =
super.cache.getClass().getDeclaredMethods();
@@ -220,18 +194,6 @@
"uid: fifo" + Integer.toString(i) + ".user" + Integer.toString(i))
);
}
- testFSEntriesList = new ArrayList<Entry>(super.NUMTESTENTRIES);
- for(int i = 0; i < super.NUMTESTENTRIES; i++ ) {
- testFSEntriesList.add(TestCaseUtils.makeEntry(
- "dn: uid=fs" + Integer.toString(i) + ".user" + Integer.toString(i)
- + ",ou=test" + Integer.toString(i) + ",o=test",
- "objectClass: person",
- "objectClass: inetorgperson",
- "objectClass: top",
- "objectClass: organizationalperson",
- "uid: fs" + Integer.toString(i) + ".user" + Integer.toString(i))
- );
- }
// Force GC to make sure we have enough memory for
// the cache capping constraints to work properly.
@@ -267,12 +229,6 @@
for (EntryCache<?> entryCache : cacheOrderMap.values()) {
entryCache.finalizeEntryCache();
}
-
- // Remove default FS cache JE environment.
- FileSystemEntryCacheCfg config = (FileSystemEntryCacheCfg)
- AdminTestCaseUtils.getConfiguration(EntryCacheCfgDefn.getInstance(),
- cacheFSConfigEntry);
- TestCaseUtils.deleteDirectory(new File(config.getCacheDirectory()));
}
@@ -455,7 +411,6 @@
for (int i = 0; i < NUMTESTENTRIES; i++) {
super.cache.putEntry(testSoftRefEntriesList.get(i), b, i);
super.cache.putEntry(testFIFOEntriesList.get(i), b, i);
- super.cache.putEntry(testFSEntriesList.get(i), b, i);
}
// Ensure all test entries are available via default cache.
@@ -472,12 +427,6 @@
testFIFOEntriesList.get(0).getName() +
" in the cache. Cache contents:" +
ServerConstants.EOL + cache.toVerboseString());
- assertNotNull(super.cache.getEntry(
- testFSEntriesList.get(0).getName()),
- "Expected to find " +
- testFSEntriesList.get(0).getName() +
- " in the cache. Cache contents:" +
- ServerConstants.EOL + cache.toVerboseString());
}
// Ensure all test entries landed on their levels.
@@ -494,12 +443,6 @@
testFIFOEntriesList.get(0).getName() +
" in the cache. Cache contents:" +
ServerConstants.EOL + cache.toVerboseString());
- assertNotNull(fsCache.getEntry(
- testFSEntriesList.get(0).getName()),
- "Expected to find " +
- testFSEntriesList.get(0).getName() +
- " in the cache. Cache contents:" +
- ServerConstants.EOL + cache.toVerboseString());
}
// Clear the cache so that other tests can start from scratch.
diff --git a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/FileSystemEntryCacheTestCase.java b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/FileSystemEntryCacheTestCase.java
deleted file mode 100644
index 2706fd0..0000000
--- a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/FileSystemEntryCacheTestCase.java
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * 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 legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * 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 legal-notices/CDDLv1_0.txt.
- * 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 2007-2008 Sun Microsystems, Inc.
- * Portions Copyright 2011-2014 ForgeRock AS
- */
-package org.opends.server.extensions;
-
-
-
-import java.io.File;
-import java.util.ArrayList;
-import org.opends.server.TestCaseUtils;
-import org.opends.server.admin.server.AdminTestCaseUtils;
-import org.testng.annotations.BeforeClass;
-import org.opends.server.admin.std.meta.*;
-import org.opends.server.admin.std.server.FileSystemEntryCacheCfg;
-import org.opends.server.api.Backend;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.util.ServerConstants;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-
-
-/**
- * A set of test cases for FileSystem entry cache implementation.
- */
-@Test(groups = "entrycache", sequential=true)
-public class FileSystemEntryCacheTestCase
- extends CommonEntryCacheTestCase<FileSystemEntryCacheCfg>
-{
- /**
- * Configuration entry for this cache.
- */
- private Entry cacheConfigEntry;
-
- /**
- * Temporary folder to setup dummy JE backend environment in.
- */
- private File jeBackendTempDir;
-
- /**
- * Utility method to restore default cache configuration.
- */
- private void restoreCacheDefaults()
- throws Exception
- {
- // Finalize this cache so it can be reconfigured.
- super.cache.finalizeEntryCache();
-
- // Configure this cache back to defaults.
- super.configuration = AdminTestCaseUtils.getConfiguration(
- FileSystemEntryCacheCfgDefn.getInstance(), cacheConfigEntry);
-
- // Initialize the cache.
- super.cache = new FileSystemEntryCache();
- super.cache.initializeEntryCache(configuration);
-
- // Make sure the cache is empty.
- assertNull(cache.toVerboseString(),
- "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
-
-
- /**
- * Utility method to configure the cache with LRU access order.
- */
- private void setupLRUCache()
- throws Exception
- {
- // Finalize this cache so it can be reconfigured.
- super.cache.finalizeEntryCache();
-
- // Configure this cache as LRU.
- Entry newCacheConfigEntry = cacheConfigEntry.duplicate(true);
- Attribute cacheConfigTypeAttr =
- Attributes.create("ds-cfg-cache-type", "LRU");
- newCacheConfigEntry.addAttribute(cacheConfigTypeAttr, null);
- super.configuration = AdminTestCaseUtils.getConfiguration(
- FileSystemEntryCacheCfgDefn.getInstance(), newCacheConfigEntry);
-
- // Initialize the cache.
- super.cache = new FileSystemEntryCache();
- super.cache.initializeEntryCache(configuration);
-
- // Make sure the cache is empty.
- assertNull(cache.toVerboseString(),
- "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
-
-
- /**
- * Utility method to initialize persistent cache.
- */
- private void persistentCacheSetup()
- throws Exception
- {
- // Make sure JE directory exist.
- jeBackendTempDir = TestCaseUtils.createTemporaryDirectory("db-cachetest");
- String jeDir = jeBackendTempDir.getAbsolutePath();
-
- // Create dummy JE backend for this test.
- TestCaseUtils.dsconfig("create-backend", "--backend-name", "cacheTest",
- "--type", "local-db", "--set", "db-directory:" + jeDir, "--set",
- "base-dn:o=cachetest", "--set",
- "writability-mode:enabled", "--set", "enabled:true");
-
- // Finalize this cache so it can be reconfigured.
- super.cache.finalizeEntryCache();
-
- // Configure this cache as persistent cache with
- // unlimited number of entries.
- Entry newCacheConfigEntry = cacheConfigEntry.duplicate(true);
- Attribute cacheConfigPersistAttr =
- Attributes.create("ds-cfg-persistent-cache", "true");
- newCacheConfigEntry.addAttribute(cacheConfigPersistAttr, null);
- Attribute cacheConfigMaxAttr =
- Attributes.create("ds-cfg-max-entries", Integer.toString(super.MAXENTRIES));
- newCacheConfigEntry.removeAttribute(cacheConfigMaxAttr, null);
- super.configuration = AdminTestCaseUtils.getConfiguration(
- FileSystemEntryCacheCfgDefn.getInstance(), newCacheConfigEntry);
-
- // Initialize the cache.
- super.cache = new FileSystemEntryCache();
- super.cache.initializeEntryCache(configuration);
-
- // Make sure the cache is empty.
- assertNull(cache.toVerboseString(),
- "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
-
-
- /**
- * Utility method to finalize persistent cache.
- */
- private void persistentCacheTeardown()
- throws Exception
- {
- // Dummy JE backend cleanup.
- TestCaseUtils.dsconfig("delete-backend", "--backend-name", "cacheTest");
- TestCaseUtils.deleteDirectory(jeBackendTempDir);
-
- // Configure this cache back to defaults.
- restoreCacheDefaults();
- }
-
-
-
- /**
- * Initialize the entry cache test.
- *
- * @throws Exception If an unexpected problem occurs.
- */
- @BeforeClass
- public void entryCacheTestInit()
- throws Exception
- {
- // Ensure that the server is running.
- TestCaseUtils.startServer();
-
- // Configure this entry cache.
- File cacheDirectory = TestCaseUtils.createTemporaryDirectory("opendj-test");
- cacheConfigEntry = TestCaseUtils.makeEntry(
- "dn: cn=File System,cn=Entry Caches,cn=config",
- "objectClass: ds-cfg-file-system-entry-cache",
- "objectClass: ds-cfg-entry-cache",
- "objectClass: top",
- "cn: File System",
- "ds-cfg-cache-level: 1",
- "ds-cfg-java-class: " +
- "org.opends.server.extensions.FileSystemEntryCache",
- "ds-cfg-enabled: true",
- "ds-cfg-max-entries: " + Integer.toString(super.MAXENTRIES),
- "ds-cfg-cache-directory: " + cacheDirectory.getAbsolutePath());
- super.configuration = AdminTestCaseUtils.getConfiguration(
- FileSystemEntryCacheCfgDefn.getInstance(), cacheConfigEntry);
-
- // Force GC to make sure we have enough memory for
- // the cache capping constraints to work properly.
- System.gc();
-
- // Initialize the cache.
- super.cache = new FileSystemEntryCache();
- super.cache.initializeEntryCache(configuration);
-
- // Make some dummy test entries.
- super.testEntriesList = new ArrayList<Entry>(super.NUMTESTENTRIES);
- for(int i = 0; i < super.NUMTESTENTRIES; i++ ) {
- super.testEntriesList.add(TestCaseUtils.makeEntry(
- "dn: uid=test" + Integer.toString(i) + ".user" + Integer.toString(i)
- + ",ou=test" + Integer.toString(i) + ",o=test",
- "objectClass: person",
- "objectClass: inetorgperson",
- "objectClass: top",
- "objectClass: organizationalperson",
- "postalAddress: somewhere in Testville" + Integer.toString(i),
- "street: Under Construction Street" + Integer.toString(i),
- "l: Testcounty" + Integer.toString(i),
- "st: Teststate" + Integer.toString(i),
- "telephoneNumber: +878 8378 8378" + Integer.toString(i),
- "mobile: +878 8378 8378" + Integer.toString(i),
- "homePhone: +878 8378 8378" + Integer.toString(i),
- "pager: +878 8378 8378" + Integer.toString(i),
- "mail: test" + Integer.toString(i) + ".user" + Integer.toString(i)
- + "@testdomain.net",
- "postalCode: 8378" + Integer.toString(i),
- "userPassword: testpassword" + Integer.toString(i),
- "description: description for Test" + Integer.toString(i) + "User"
- + Integer.toString(i),
- "cn: Test" + Integer.toString(i) + "User" + Integer.toString(i),
- "sn: User" + Integer.toString(i),
- "givenName: Test" + Integer.toString(i),
- "initials: TST" + Integer.toString(i),
- "employeeNumber: 8378" + Integer.toString(i),
- "uid: test" + Integer.toString(i) + ".user" + Integer.toString(i))
- );
- }
- }
-
-
-
- /**
- * Finalize the entry cache test.
- *
- * @throws Exception If an unexpected problem occurs.
- */
- @AfterClass
- public void entryCacheTestFini()
- throws Exception
- {
- super.cache.finalizeEntryCache();
-
- // Remove default FS cache JE environment.
- FileSystemEntryCacheCfg config = super.configuration;
- TestCaseUtils.deleteDirectory(new File(config.getCacheDirectory()));
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testContainsEntry()
- throws Exception
- {
- super.testContainsEntry();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testGetEntry1()
- throws Exception
- {
- super.testGetEntry1();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testGetEntry2()
- throws Exception
- {
- super.testGetEntry2();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testGetEntry3()
- throws Exception
- {
- super.testGetEntry3();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testGetEntryID()
- throws Exception
- {
- super.testGetEntryID();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testPutEntry()
- throws Exception
- {
- super.testPutEntry();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testPutEntryIfAbsent()
- throws Exception
- {
- super.testPutEntryIfAbsent();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testRemoveEntry()
- throws Exception
- {
- super.testRemoveEntry();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testClear()
- throws Exception
- {
- super.testClear();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testClearBackend()
- throws Exception
- {
- super.testClearBackend();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testClearSubtree()
- throws Exception
- {
- super.testClearSubtree();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test()
- @Override
- public void testHandleLowMemory()
- throws Exception
- {
- super.testHandleLowMemory();
- }
-
-
-
- @BeforeGroups(groups = "testFSFIFOCacheConcurrency")
- public void cacheConcurrencySetup()
- throws Exception
- {
- assertNull(cache.toVerboseString(),
- "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
-
-
- @AfterGroups(groups = "testFSFIFOCacheConcurrency")
- public void cacheConcurrencyCleanup()
- throws Exception
- {
- // Clear the cache so that other tests can start from scratch.
- super.cache.clear();
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Test(groups = { "slow", "testFSFIFOCacheConcurrency" },
- threadPoolSize = 10,
- invocationCount = 10,
- // In case of disk based FS.
- timeOut = 600000)
- @Override
- public void testCacheConcurrency()
- throws Exception
- {
- super.testCacheConcurrency();
- }
-
-
-
- @BeforeGroups(groups = "testFSLRUCacheConcurrency")
- public void LRUCacheConcurrencySetup()
- throws Exception
- {
- // Setup LRU cache.
- setupLRUCache();
- }
-
-
-
- @AfterGroups(groups = "testFSLRUCacheConcurrency")
- public void LRUCacheConcurrencyCleanup()
- throws Exception
- {
- // Configure this cache back to defaults.
- restoreCacheDefaults();
- }
-
-
-
- /**
- * Tests the entry cache concurrency/threadsafety by executing
- * core entry cache operations on several threads concurrently
- * on LRU access order cache.
- *
- * @throws Exception If an unexpected problem occurs.
- */
- @Test(groups = { "slow", "testFSLRUCacheConcurrency" },
- threadPoolSize = 10,
- invocationCount = 10,
- // In case of disk based FS.
- timeOut = 600000)
- public void testLRUCacheConcurrency()
- throws Exception
- {
- super.testCacheConcurrency();
- }
-
-
-
- /**
- * Tests FIFO cache rotation on specific number of entries.
- */
- @Test(groups = "slow")
- public void testCacheRotationFIFO()
- throws Exception
- {
- assertNull(cache.toVerboseString(),
- "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
-
- // Put some test entries in the cache.
- Backend b = DirectoryServer.getBackend(DN.valueOf("o=test"));
- for(int i = 0; i < super.NUMTESTENTRIES; i++ ) {
- super.cache.putEntry(super.testEntriesList.get(i), b, i);
- }
-
- // Make sure first NUMTESTENTRIES - MAXENTRIES got rotated.
- for(int i = 0; i < (super.NUMTESTENTRIES - super.MAXENTRIES); i++ ) {
- assertFalse(super.cache.containsEntry(
- super.testEntriesList.get(i).getName()), "Not expected to find " +
- super.testEntriesList.get(i).getName() + " in the " +
- "cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
- // Make sure remaining NUMTESTENTRIES are still in the cache.
- for(int i = (super.NUMTESTENTRIES - super.MAXENTRIES);
- i < super.NUMTESTENTRIES;
- i++)
- {
- assertTrue(super.cache.containsEntry(
- super.testEntriesList.get(i).getName()), "Expected to find " +
- super.testEntriesList.get(i).getName() + " in the " +
- "cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
- // Clear the cache so that other tests can start from scratch.
- super.cache.clear();
- }
-
-
-
- /**
- * Tests LRU cache rotation on specific number of entries.
- */
- @Test(groups = "slow")
- public void testCacheRotationLRU()
- throws Exception
- {
- // Setup LRU cache.
- setupLRUCache();
-
- // Put some test entries in the cache.
- Backend b = DirectoryServer.getBackend(DN.valueOf("o=test"));
- for(int i = 0; i < super.NUMTESTENTRIES; i++) {
- super.cache.putEntry(super.testEntriesList.get(i), b, i);
- // Sacrifice one cache entry to support rotation.
- for(int j = 0; j < (super.MAXENTRIES - 1); j++) {
- // Generate access.
- super.cache.getEntry(super.testEntriesList.get(j).getName());
- }
- }
-
- // Make sure MAXENTRIES - 1 are still in the cache.
- for(int i = 0; i < (super.MAXENTRIES - 1); i++) {
- assertTrue(super.cache.containsEntry(
- super.testEntriesList.get(i).getName()),
- "Expected to find " +
- super.testEntriesList.get(i).getName() + " in the " +
- "cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
- // Plus the last cache entry added.
- assertTrue(super.cache.containsEntry(
- super.testEntriesList.get(super.NUMTESTENTRIES - 1).getName()),
- "Expected to find " +
- super.testEntriesList.get(super.NUMTESTENTRIES - 1).getName() +
- " in the cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
-
- // And remaining NUMTESTENTRIES - 1 are now rotated.
- for(int i = (super.MAXENTRIES - 1);
- i < (super.NUMTESTENTRIES - 1);
- i++) {
- assertFalse(super.cache.containsEntry(
- super.testEntriesList.get(i).getName()),
- "Not expected to find " +
- super.testEntriesList.get(i).getName() + " in the " +
- "cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
- // Clear the cache so that other tests can start from scratch.
- super.cache.clear();
-
- // Configure this cache back to defaults.
- restoreCacheDefaults();
- }
-
-
-
- /**
- * Tests cache persistence with consistent backend.
- */
- @Test(groups = "slow")
- public void testCachePersistence()
- throws Exception
- {
- // Setup this test.
- persistentCacheSetup();
-
- // Put some test entries in the cache.
- Backend b = DirectoryServer.getBackend(DN.valueOf("o=cachetest"));
- for(int i = 0; i < super.NUMTESTENTRIES; i++) {
- super.cache.putEntry(super.testEntriesList.get(i), b, i);
- }
-
- // Should trigger backend checksum.
- b.finalizeBackend();
-
- // Finalize and persist this cache.
- super.cache.finalizeEntryCache();
-
- // Get cachetest backend online again.
- b.initializeBackend();
-
- // Initialize the cache again.
- super.cache = new FileSystemEntryCache();
- super.cache.initializeEntryCache(configuration);
-
- // Check that this cache is persistent indeed.
- for(int i = 0; i < super.NUMTESTENTRIES; i++) {
- assertTrue(super.cache.containsEntry(
- super.testEntriesList.get(i).getName()),
- "Expected to find " +
- super.testEntriesList.get(i).getName() + " in the " +
- "cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
- // Clear the cache so that other tests can start from scratch.
- super.cache.clear();
-
- // Finalize this cache so it can be reconfigured.
- super.cache.finalizeEntryCache();
-
- // Clean up.
- b.finalizeBackend();
- persistentCacheTeardown();
- }
-
-
-
- /**
- * Tests cache persistence with inconsistent backend.
- */
- @Test(groups = "slow")
- public void testCachePersistenceInconsistent()
- throws Exception
- {
- // Setup this test.
- persistentCacheSetup();
-
- // Put some test entries in the cache.
- Backend b = DirectoryServer.getBackend(DN.valueOf("o=cachetest"));
- for(int i = 0; i < super.NUMTESTENTRIES; i++) {
- super.cache.putEntry(super.testEntriesList.get(i), b, i);
- }
-
- // Should trigger backend checksum.
- b.finalizeBackend();
-
- // Finalize and persist this cache.
- super.cache.finalizeEntryCache();
-
- // Get cachetest backend online again.
- b.initializeBackend();
-
- // Add dummy entry to cachetest backend to trigger inconsistent
- // offline state with persistent entry cache.
- TestCaseUtils.addEntry(
- "dn: o=cachetest",
- "objectClass: top",
- "objectClass: organization");
-
- // Should trigger backend checksum.
- b.finalizeBackend();
-
- // Get cachetest backend online again, now modified.
- b.initializeBackend();
-
- // Initialize the cache again.
- super.cache = new FileSystemEntryCache();
- super.cache.initializeEntryCache(configuration);
-
- // Check that this cache is persistent indeed.
- for(int i = 0; i < super.NUMTESTENTRIES; i++) {
- assertFalse(super.cache.containsEntry(
- super.testEntriesList.get(i).getName()),
- "Not expected to find " +
- super.testEntriesList.get(i).getName() + " in the " +
- "cache. Cache contents:" + ServerConstants.EOL +
- cache.toVerboseString());
- }
-
- // Clear the cache so that other tests can start from scratch.
- super.cache.clear();
-
- // Finalize this cache so it can be reconfigured.
- super.cache.finalizeEntryCache();
-
- // Clean up.
- b.finalizeBackend();
- persistentCacheTeardown();
- }
-}
diff --git a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java
index 82fc914..e439725 100644
--- a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java
+++ b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java
@@ -37,7 +37,6 @@
import org.testng.annotations.BeforeClass;
import org.opends.server.admin.std.meta.*;
import org.opends.server.admin.std.server.EntryCacheCfg;
-import org.opends.server.admin.std.server.FileSystemEntryCacheCfg;
import org.opends.server.api.Backend;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Entry;
@@ -81,7 +80,6 @@
* @throws Exception If an unexpected problem occurs.
*/
@BeforeClass()
- @SuppressWarnings("unchecked")
public void preloadEntryCacheTestInit()
throws Exception
{
@@ -100,15 +98,15 @@
// Configure the entry cache, use FileSystemEntryCache.
Entry cacheConfigEntry = TestCaseUtils.makeEntry(
- "dn: cn=File System,cn=Entry Caches,cn=config",
- "objectClass: ds-cfg-file-system-entry-cache",
- "objectClass: ds-cfg-entry-cache",
- "objectClass: top",
- "cn: File System",
- "ds-cfg-cache-level: 1",
- "ds-cfg-java-class: " +
- "org.opends.server.extensions.FileSystemEntryCache",
- "ds-cfg-enabled: true");
+ "dn: cn=Soft Reference,cn=Entry Caches,cn=config",
+ "objectClass: ds-cfg-soft-reference-entry-cache",
+ "objectClass: ds-cfg-entry-cache",
+ "objectClass: top",
+ "cn: Soft Reference",
+ "ds-cfg-cache-level: 1",
+ "ds-cfg-java-class: " +
+ "org.opends.server.extensions.SoftReferenceEntryCache",
+ "ds-cfg-enabled: true");
configuration = AdminTestCaseUtils.getConfiguration(
EntryCacheCfgDefn.getInstance(), cacheConfigEntry);
@@ -225,11 +223,6 @@
// Sanity in-core restart.
TestCaseUtils.restartServer();
-
- // Remove default FS cache JE environment.
- FileSystemEntryCacheCfg config =
- (FileSystemEntryCacheCfg) configuration;
- TestCaseUtils.deleteDirectory(new File(config.getCacheDirectory()));
}
--
Gitblit v1.10.0