From 5031429bf032af5e3d8797210cc47b402ef831d6 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 16 Dec 2014 23:48:24 +0000
Subject: [PATCH] OPENDJ-1602 (CR-5566) New pluggable storage based backend

---
 opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java |  291 +++++++++++++++++++---------------------------------------
 1 files changed, 96 insertions(+), 195 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
index efc4b12..804c101 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
@@ -34,16 +34,19 @@
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.config.server.ConfigException;
-import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.LocalDBBackendCfg;
 import org.opends.server.api.Backend;
-import org.opends.server.backends.pluggable.BackendImpl.Storage;
+import org.opends.server.api.CompressedSchema;
+import org.opends.server.backends.persistit.PersistItStorage;
+import org.opends.server.backends.pluggable.BackendImpl.ReadOperation;
+import org.opends.server.backends.pluggable.BackendImpl.ReadableStorage;
 import org.opends.server.backends.pluggable.BackendImpl.StorageRuntimeException;
+import org.opends.server.backends.pluggable.BackendImpl.TreeName;
 import org.opends.server.backends.pluggable.BackendImpl.WriteOperation;
 import org.opends.server.backends.pluggable.BackendImpl.WriteableStorage;
+import org.opends.server.core.DefaultCompressedSchema;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.monitors.DatabaseEnvironmentMonitor;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.DN;
 import org.opends.server.types.FilePermission;
@@ -64,10 +67,7 @@
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
   /** The JE database environment. */
-  private Storage storage;
-
-  /** Used to force a checkpoint during import. */
-  private final CheckpointConfig importForceCheckPoint = new CheckpointConfig();
+  private PersistItStorage storage; // FIXME JNR do not hardcode here
 
   /** The backend configuration. */
   private LocalDBBackendCfg config;
@@ -84,8 +84,9 @@
   /** The cached value of the next entry identifier to be assigned. */
   private AtomicLong nextid = new AtomicLong(1);
 
+  // FIXME JNR Switch back to a database persisted implementation of CompressedSchema
   /** The compressed schema manager for this backend. */
-  private JECompressedSchema compressedSchema;
+  private CompressedSchema compressedSchema;
 
 
 
@@ -106,13 +107,16 @@
     getMonitorProvider().setMaxEntries(config.getIndexFilterAnalyzerMaxFilters());
 
     config.addLocalDBChangeListener(this);
-    importForceCheckPoint.setForce(true);
+  }
+
+  PersistItStorage getStorage()
+  {
+    return storage;
   }
 
   /**
    * Opens the root container using the JE configuration object provided.
    *
-   * @param  envConfig               The JE environment configuration.
    * @throws StorageRuntimeException       If a database error occurs when creating
    *                                 the environment.
    * @throws InitializationException If an initialization error occurs while
@@ -120,7 +124,7 @@
    * @throws ConfigException         If an configuration error occurs while
    *                                 creating the environment.
    */
-  public void open(EnvironmentConfig envConfig)
+  public void open()
       throws StorageRuntimeException, InitializationException, ConfigException
   {
     // Determine the backend database directory.
@@ -183,39 +187,26 @@
     }
 
     // Open the database environment
-    storage = new Storage(backendDirectory, envConfig);
+    storage = new PersistItStorage(backendDirectory, this.config);
 
-    if (logger.isTraceEnabled())
+    compressedSchema = new DefaultCompressedSchema();
+    try
     {
-      logger.trace("JE (%s) environment opened with the following config: %n%s",
-          JEVersion.CURRENT_VERSION, storage.getConfig());
-
-      // Get current size of heap in bytes
-      long heapSize = Runtime.getRuntime().totalMemory();
-
-      // Get maximum size of heap in bytes. The heap cannot grow beyond this size.
-      // Any attempt will result in an OutOfMemoryException.
-      long heapMaxSize = Runtime.getRuntime().maxMemory();
-
-      // Get amount of free memory within the heap in bytes. This size will increase
-      // after garbage collection and decrease as new objects are created.
-      long heapFreeSize = Runtime.getRuntime().freeMemory();
-
-      logger.trace("Current size of heap: %d bytes", heapSize);
-      logger.trace("Max size of heap: %d bytes", heapMaxSize);
-      logger.trace("Free memory in heap: %d bytes", heapFreeSize);
-    }
-
-    compressedSchema = new JECompressedSchema(storage);
-
-    storage.write(new WriteOperation()
-    {
-      @Override
-      public void run(WriteableStorage txn) throws Exception
+      storage.initialize(null);
+      storage.open();
+      storage.write(new WriteOperation()
       {
-        openAndRegisterEntryContainers(txn, config.getBaseDN());
-      }
-    });
+        @Override
+        public void run(WriteableStorage txn) throws Exception
+        {
+          openAndRegisterEntryContainers(txn, config.getBaseDN());
+        }
+      });
+    }
+    catch (Exception e)
+    {
+      throw new StorageRuntimeException(e);
+    }
   }
 
   /**
@@ -248,13 +239,26 @@
       databasePrefix = name;
     }
 
-    EntryContainer ec = new EntryContainer(baseDN, databasePrefix,
+    EntryContainer ec = new EntryContainer(baseDN, toSuffixName(databasePrefix),
                                            backend, config, storage, this);
     ec.open(txn);
     return ec;
   }
 
   /**
+   * Transform a database prefix string to one usable by the DB.
+   *
+   * @param databasePrefix
+   *          the database prefix
+   * @return a new string when non letter or digit characters have been replaced
+   *         with underscore
+   */
+  private TreeName toSuffixName(String databasePrefix)
+  {
+    return TreeName.of(storage.toSuffixName(databasePrefix));
+  }
+
+  /**
    * Registers the entry container for a base DN.
    *
    * @param baseDN The base DN of the entry container to close.
@@ -325,7 +329,7 @@
    *
    * @return  The compressed schema manager for this backend.
    */
-  public JECompressedSchema getCompressedSchema()
+  public CompressedSchema getCompressedSchema()
   {
     return compressedSchema;
   }
@@ -537,35 +541,6 @@
   }
 
   /**
-   * Get the environment transaction stats of the JE environment used
-   * in this root container.
-   *
-   * @param statsConfig The configuration to use for the EnvironmentStats
-   *                    object.
-   * @return The environment status of the JE environment.
-   * @throws StorageRuntimeException If an error occurs while retrieving the stats
-   *                           object.
-   */
-  public TransactionStats getEnvironmentTransactionStats(
-      StatsConfig statsConfig) throws StorageRuntimeException
-  {
-    return storage.getTransactionStats(statsConfig);
-  }
-
-  /**
-   * Get the environment config of the JE environment used in this root
-   * container.
-   *
-   * @return The environment config of the JE environment.
-   * @throws StorageRuntimeException If an error occurs while retrieving the
-   *                           configuration object.
-   */
-  public EnvironmentConfig getEnvironmentConfig() throws StorageRuntimeException
-  {
-    return storage.getConfig();
-  }
-
-  /**
    * Get the backend configuration used by this root container.
    *
    * @return The JE backend configuration used by this root container.
@@ -584,21 +559,34 @@
    */
   public long getEntryCount() throws StorageRuntimeException
   {
-    long entryCount = 0;
-    for(EntryContainer ec : this.entryContainers.values())
+    try
     {
-      ec.sharedLock.lock();
-      try
+      return storage.read(new ReadOperation<Long>()
       {
-        entryCount += ec.getEntryCount();
-      }
-      finally
-      {
-        ec.sharedLock.unlock();
-      }
+        @Override
+        public Long run(ReadableStorage txn) throws Exception
+        {
+          long entryCount = 0;
+          for (EntryContainer ec : entryContainers.values())
+          {
+            ec.sharedLock.lock();
+            try
+            {
+              entryCount += ec.getEntryCount(txn);
+            }
+            finally
+            {
+              ec.sharedLock.unlock();
+            }
+          }
+          return entryCount;
+        }
+      });
     }
-
-    return entryCount;
+    catch (Exception e)
+    {
+      throw new StorageRuntimeException(e);
+    }
   }
 
   /**
@@ -705,81 +693,10 @@
   @Override
   public ConfigChangeResult applyConfigurationChange(LocalDBBackendCfg cfg)
   {
-    boolean adminActionRequired = false;
-    ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
+    final ConfigChangeResult ccr = new ConfigChangeResult();
 
     try
     {
-      if(storage != null)
-      {
-        // Check if any JE non-mutable properties were changed.
-        EnvironmentConfig oldEnvConfig = storage.getConfig();
-        EnvironmentConfig newEnvConfig =
-            ConfigurableEnvironment.parseConfigEntry(cfg);
-        Map<?,?> paramsMap = EnvironmentParams.SUPPORTED_PARAMS;
-
-        // Iterate through native JE properties.
-        SortedSet<String> jeProperties = cfg.getJEProperty();
-        for (String jeEntry : jeProperties) {
-          // There is no need to validate properties yet again.
-          StringTokenizer st = new StringTokenizer(jeEntry, "=");
-          if (st.countTokens() == 2) {
-            String jePropertyName = st.nextToken();
-            String jePropertyValue = st.nextToken();
-            ConfigParam param = (ConfigParam) paramsMap.get(jePropertyName);
-            if (!param.isMutable()) {
-              String oldValue = oldEnvConfig.getConfigParam(param.getName());
-              if (!oldValue.equalsIgnoreCase(jePropertyValue)) {
-                adminActionRequired = true;
-                messages.add(INFO_CONFIG_JE_PROPERTY_REQUIRES_RESTART.get(jePropertyName));
-                if(logger.isTraceEnabled()) {
-                  logger.trace("The change to the following property " +
-                    "will take effect when the component is restarted: " +
-                    jePropertyName);
-                }
-              }
-            }
-          }
-        }
-
-        // Iterate through JE configuration attributes.
-        for (Object o : paramsMap.values())
-        {
-          ConfigParam param = (ConfigParam) o;
-          if (!param.isMutable())
-          {
-            String oldValue = oldEnvConfig.getConfigParam(param.getName());
-            String newValue = newEnvConfig.getConfigParam(param.getName());
-            if (!oldValue.equalsIgnoreCase(newValue))
-            {
-              adminActionRequired = true;
-              String configAttr = ConfigurableEnvironment.
-                  getAttributeForProperty(param.getName());
-              if (configAttr != null)
-              {
-                messages.add(NOTE_JEB_CONFIG_ATTR_REQUIRES_RESTART.get(configAttr));
-              }
-              else
-              {
-                messages.add(NOTE_JEB_CONFIG_ATTR_REQUIRES_RESTART.get(param.getName()));
-              }
-              if(logger.isTraceEnabled())
-              {
-                logger.trace("The change to the following property will " +
-                    "take effect when the backend is restarted: " +
-                    param.getName());
-              }
-            }
-          }
-        }
-
-        // This takes care of changes to the JE environment for those
-        // properties that are mutable at runtime.
-        storage.setMutableConfig(newEnvConfig);
-
-        logger.trace("JE database configuration: %s", storage.getConfig());
-      }
-
       // Create the directory if it doesn't exist.
       if(!cfg.getDBDirectory().equals(this.config.getDBDirectory()))
       {
@@ -791,31 +708,25 @@
         {
           if(!backendDirectory.mkdirs())
           {
-            messages.add(ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath()));
-            return new ConfigChangeResult(
-                DirectoryServer.getServerErrorResultCode(),
-                adminActionRequired,
-                messages);
+            ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+            ccr.addMessage(ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath()));
+            return ccr;
           }
         }
         //Make sure the directory is valid.
         else if (!backendDirectory.isDirectory())
         {
-          messages.add(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
-          return new ConfigChangeResult(
-              DirectoryServer.getServerErrorResultCode(),
-              adminActionRequired,
-              messages);
+          ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+          ccr.addMessage(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
+          return ccr;
         }
 
-        adminActionRequired = true;
-        messages.add(NOTE_JEB_CONFIG_DB_DIR_REQUIRES_RESTART.get(
-                        this.config.getDBDirectory(), cfg.getDBDirectory()));
+        ccr.setAdminActionRequired(true);
+        ccr.addMessage(NOTE_JEB_CONFIG_DB_DIR_REQUIRES_RESTART.get(this.config.getDBDirectory(), cfg.getDBDirectory()));
       }
 
-      if(!cfg.getDBDirectoryPermissions().equalsIgnoreCase(
-          config.getDBDirectoryPermissions()) ||
-          !cfg.getDBDirectory().equals(this.config.getDBDirectory()))
+      if (!cfg.getDBDirectoryPermissions().equalsIgnoreCase(config.getDBDirectoryPermissions())
+          || !cfg.getDBDirectory().equals(this.config.getDBDirectory()))
       {
         FilePermission backendPermission;
         try
@@ -825,25 +736,19 @@
         }
         catch(Exception e)
         {
-          messages.add(ERR_CONFIG_BACKEND_MODE_INVALID.get(config.dn()));
-          return new ConfigChangeResult(
-              DirectoryServer.getServerErrorResultCode(),
-              adminActionRequired,
-              messages);
+          ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+          ccr.addMessage(ERR_CONFIG_BACKEND_MODE_INVALID.get(config.dn()));
+          return ccr;
         }
 
-        //Make sure the mode will allow the server itself access to
-        //the database
+        // Make sure the mode will allow the server itself access to the database
         if(!backendPermission.isOwnerWritable() ||
             !backendPermission.isOwnerReadable() ||
             !backendPermission.isOwnerExecutable())
         {
-          messages.add(ERR_CONFIG_BACKEND_INSANE_MODE.get(
-              cfg.getDBDirectoryPermissions()));
-          return new ConfigChangeResult(
-              DirectoryServer.getServerErrorResultCode(),
-              adminActionRequired,
-              messages);
+          ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+          ccr.addMessage(ERR_CONFIG_BACKEND_INSANE_MODE.get(cfg.getDBDirectoryPermissions()));
+          return ccr;
         }
 
         // Get the backend database backendDirectory permissions and apply
@@ -866,22 +771,18 @@
         }
       }
 
-      getMonitorProvider().enableFilterUseStats(
-          cfg.isIndexFilterAnalyzerEnabled());
-      getMonitorProvider()
-          .setMaxEntries(cfg.getIndexFilterAnalyzerMaxFilters());
+      getMonitorProvider().enableFilterUseStats(cfg.isIndexFilterAnalyzerEnabled());
+      getMonitorProvider().setMaxEntries(cfg.getIndexFilterAnalyzerMaxFilters());
 
       this.config = cfg;
     }
     catch (Exception e)
     {
-      messages.add(LocalizableMessage.raw(stackTraceToSingleLineString(e)));
-      return new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
-                                   adminActionRequired,
-                                   messages);
+      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+      ccr.addMessage(LocalizableMessage.raw(stackTraceToSingleLineString(e)));
+      return ccr;
     }
-
-    return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages);
+    return ccr;
   }
 
   /**

--
Gitblit v1.10.0