From ffb9044301d1c169f934e0adf4f473e99da39a47 Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Mon, 27 Aug 2007 18:58:10 +0000
Subject: [PATCH] This adds the numSubordinates and hasSubordinates operational attribute support in OpenDS.    - Implemented as virtual attributes    - They are enabled by default    - numSubordinates and hasSubordinates methods added to the backend API and implemented for all existing backends    - JE implementation uses the id2children index to keep count of the number of subordinates for each entry.    - The behavior of exceeding the index-entry-limit (ALL-IDs) has changed to store a 8 byte entry ID set count with the most significant bit  set to 1 instead of a 0 byte array to signify the index-entry-limit has been exceeded. The previous format is still compatible but all requests  for numSubordinates will return undefined (-1).    - The DBTest tool is also included in this fix. This can be used to list root containers, entry containers, database containers, index  status, as well as dumping a database with or without decoding the data. 

---
 opends/src/server/org/opends/server/backends/jeb/BackendImpl.java |  101 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java b/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
index cc8b802..b9a7956 100644
--- a/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
+++ b/opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
@@ -311,7 +311,7 @@
       EnvironmentConfig envConfig =
           ConfigurableEnvironment.parseConfigEntry(cfg);
 
-      initializeRootContainer(envConfig);
+      rootContainer = initializeRootContainer(envConfig);
     }
 
     // Preload the database cache.
@@ -598,7 +598,63 @@
     return -1;
   }
 
+  /**
+   * {@inheritDoc}
+   */
+  public ConditionResult hasSubordinates(DN entryDN) throws DirectoryException
+  {
+    long ret = numSubordinates(entryDN);
+    if(ret < 0)
+    {
+      return ConditionResult.UNDEFINED;
+    }
+    else if(ret == 0)
+    {
+      return ConditionResult.FALSE;
+    }
+    else
+    {
+      return ConditionResult.TRUE;
+    }
+  }
 
+  /**
+   * {@inheritDoc}
+   */
+  public long numSubordinates(DN entryDN) throws DirectoryException
+  {
+    EntryContainer ec = rootContainer.getEntryContainer(entryDN);
+    if(ec == null)
+    {
+      return -1;
+    }
+
+    readerBegin();
+    ec.sharedLock.lock();
+    try
+    {
+      long count = ec.getNumSubordinates(entryDN);
+      if(count == Long.MAX_VALUE)
+      {
+        // The index entry limit has exceeded and there is no count maintained.
+        return -1;
+      }
+      return count;
+    }
+    catch (DatabaseException e)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+      throw createDirectoryException(e);
+    }
+    finally
+    {
+      ec.sharedLock.unlock();
+      readerEnd();
+    }
+  }
 
   /**
    * Retrieves the requested entry from this backend.  Note that the caller must
@@ -938,7 +994,7 @@
         envConfig.setConfigParam("je.env.isLocking", "true");
         envConfig.setConfigParam("je.env.runCheckpointer", "true");
 
-        initializeRootContainer(envConfig);
+        rootContainer = initializeRootContainer(envConfig);
       }
 
 
@@ -1081,7 +1137,7 @@
         envConfig.setConfigParam("je.env.runCheckpointer", "false");
       }
 
-      initializeRootContainer(envConfig);
+      rootContainer = initializeRootContainer(envConfig);
 
       ImportJob importJob = new ImportJob(importConfig);
       return importJob.importLDIF(rootContainer);
@@ -1192,7 +1248,7 @@
         envConfig.setConfigParam("je.env.isLocking", "true");
         envConfig.setConfigParam("je.env.runCheckpointer", "true");
 
-        initializeRootContainer(envConfig);
+        rootContainer = initializeRootContainer(envConfig);
       }
 
       VerifyJob verifyJob = new VerifyJob(verifyConfig);
@@ -1275,7 +1331,7 @@
         EnvironmentConfig envConfig =
             ConfigurableEnvironment.parseConfigEntry(cfg);
 
-        initializeRootContainer(envConfig);
+        rootContainer = initializeRootContainer(envConfig);
       }
 
       RebuildJob rebuildJob = new RebuildJob(rebuildConfig);
@@ -1502,6 +1558,34 @@
   }
 
   /**
+   * Returns a new read-only handle to the JE root container for this backend.
+   * The caller is responsible for closing the root container after use.
+   *
+   * @return The read-only RootContainer object for this backend.
+   *
+   * @throws  ConfigException  If an unrecoverable problem arises during
+   *                           initialization.
+   * @throws  InitializationException  If a problem occurs during initialization
+   *                                   that is not related to the server
+   *                                   configuration.
+   */
+  public RootContainer getReadOnlyRootContainer()
+      throws ConfigException, InitializationException
+  {
+    EnvironmentConfig envConfig =
+        ConfigurableEnvironment.parseConfigEntry(cfg);
+
+    envConfig.setReadOnly(true);
+    envConfig.setAllowCreate(false);
+    envConfig.setTransactional(false);
+    envConfig.setTxnNoSync(false);
+    envConfig.setConfigParam("je.env.isLocking", "true");
+    envConfig.setConfigParam("je.env.runCheckpointer", "true");
+
+    return initializeRootContainer(envConfig);
+  }
+
+  /**
    * Clears all the entries from the backend.  This method is for test cases
    * that use the JE backend.
    *
@@ -1589,14 +1673,15 @@
     return cfg.dn();
   }
 
-  private void initializeRootContainer(EnvironmentConfig envConfig)
+  private RootContainer initializeRootContainer(EnvironmentConfig envConfig)
       throws ConfigException, InitializationException
   {
     // Open the database environment
     try
     {
-      rootContainer = new RootContainer(this, cfg);
-      rootContainer.open(envConfig);
+      RootContainer rc = new RootContainer(this, cfg);
+      rc.open(envConfig);
+      return rc;
     }
     catch (DatabaseException e)
     {

--
Gitblit v1.10.0