mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

boli
22.47.2007 9a72955d0b08a0a1b3116d9eaba993c77c84d8c1
Added the ability to retrieve the number of entries in the entire subordinate subtree to the numSubordinates method in the backend API. Changed the replication code to use numSubordinates of the entires subtree to determine how many entries will be exported and imported during initialization.

Fix for issue 2212
17 files modified
264 ■■■■■ changed files
opends/src/server/org/opends/server/api/Backend.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/BackupBackend.java 22 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/LDIFBackend.java 18 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/MemoryBackend.java 19 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/MonitorBackend.java 6 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/RootDSEBackend.java 20 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/SchemaBackend.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/TrustStoreBackend.java 11 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/BackendImpl.java 34 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/EntryContainer.java 17 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/TaskBackend.java 15 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java 29 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java 6 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java 8 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java 2 ●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/LDIFBackendTestCase.java 11 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java 36 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/Backend.java
@@ -433,13 +433,19 @@
   *
   * @param entryDN The distinguished name of the entry.
   *
   * @param subtree <code>true</code> to include all entries from the
   *                      requested entry to the lowest level in the
   *                      tree or <code>false</code> to only include
   *                      the entries immediately below the requested
   *                      entry.
   *
   * @return The number of subordinate entries for the requested entry
   *         or -1 if it can not be determined.
   *
   * @throws DirectoryException  If a problem occurs while trying to
   *                              retrieve the entry.
   */
  public abstract long numSubordinates(DN entryDN)
  public abstract long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException;
opends/src/server/org/opends/server/backends/BackupBackend.java
@@ -357,7 +357,7 @@
  @Override()
  public ConditionResult hasSubordinates(DN entryDN) throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    {
      return ConditionResult.UNDEFINED;
@@ -378,7 +378,8 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN) throws DirectoryException
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    // If the requested entry was null, then return undefined.
    if (entryDN == null)
@@ -400,6 +401,23 @@
        {
          continue;
        }
        // If subtree is included, count the number of entries for each
        // backup directory.
        if (subtree)
        {
          try
          {
            BackupDirectory backupDirectory =
                BackupDirectory.readBackupDirectoryDescriptor(f.getPath());
            count += backupDirectory.getBackups().keySet().size();
          }
          catch (Exception e)
          {
            return -1;
          }
        }
        count ++;
      }
      return count;
opends/src/server/org/opends/server/backends/LDIFBackend.java
@@ -500,7 +500,7 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN)
  public long numSubordinates(DN entryDN, boolean subtree)
         throws DirectoryException
  {
    backendLock.readLock().lock();
@@ -525,7 +525,21 @@
      }
      else
      {
        return childDNSet.size();
        if(!subtree)
        {
          return childDNSet.size();
        }
        else
        {
          long count = 0;
          for(DN childDN : childDNSet)
          {
            count += numSubordinates(childDN, true);
            count ++;
          }
          return count;
        }
      }
    }
    finally
opends/src/server/org/opends/server/backends/MemoryBackend.java
@@ -326,7 +326,7 @@
  public synchronized ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    {
      return ConditionResult.UNDEFINED;
@@ -345,7 +345,7 @@
   * {@inheritDoc}
   */
  @Override()
  public synchronized long numSubordinates(DN entryDN)
  public synchronized long numSubordinates(DN entryDN, boolean subtree)
         throws DirectoryException
  {
    // Try to look up the immediate children for the DN
@@ -360,7 +360,20 @@
      return -1;
    }
    return children.size();
    if(!subtree)
    {
      return children.size();
    }
    else
    {
      long count = 0;
      for(DN child : children)
      {
        count += numSubordinates(child, true);
        count++;
      }
      return count;
    }
  }
  /**
opends/src/server/org/opends/server/backends/MonitorBackend.java
@@ -373,7 +373,7 @@
  public ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    {
      return ConditionResult.UNDEFINED;
@@ -394,7 +394,7 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN)
  public long numSubordinates(DN entryDN, boolean subtree)
         throws DirectoryException
  {
    // If the requested entry was null, then return undefined.
@@ -408,6 +408,8 @@
    // the number of monitor providers.
    if (entryDN.equals(baseMonitorDN))
    {
      // This backend is only 1 level deep so the count is the same for
      // subtree and immediate subordinates.
      return DirectoryServer.getMonitorProviders().size();
    }
opends/src/server/org/opends/server/backends/RootDSEBackend.java
@@ -396,7 +396,7 @@
  public ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    {
      return ConditionResult.UNDEFINED;
@@ -417,7 +417,7 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN)
  public long numSubordinates(DN entryDN, boolean subtree)
         throws DirectoryException
  {
    if (entryDN == null || ! entryDN.isNullDN())
@@ -439,9 +439,21 @@
    for (DN subBase : baseMap.keySet())
    {
      if (DirectoryServer.entryExists(subBase))
      Backend b = baseMap.get(subBase);
      Entry subBaseEntry = b.getEntry(subBase);
      if (subBaseEntry != null)
      {
        count++;
        if(subtree)
        {
          long subCount = b.numSubordinates(subBase, true);
          if(subCount < 0)
          {
            return -1;
          }
          count += subCount;
        }
        count ++;
      }
    }
opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -622,7 +622,7 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN)
  public long numSubordinates(DN entryDN, boolean subtree)
         throws DirectoryException
  {
    return 0L;
opends/src/server/org/opends/server/backends/TrustStoreBackend.java
@@ -1002,9 +1002,10 @@
   */
  @Override()
  public ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
      throws DirectoryException
  {
    return ConditionResult.UNDEFINED;
    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
        ERR_HAS_SUBORDINATES_NOT_SUPPORTED.get());
  }
@@ -1013,9 +1014,11 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN) throws DirectoryException
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    return -1;
    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
        ERR_NUM_SUBORDINATES_NOT_SUPPORTED.get());
  }
opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
@@ -264,33 +264,6 @@
    return 0;
  }
  /**
   * This method constructs a container name from a base DN. Only alphanumeric
   * characters are preserved, all other characters are replaced with an
   * underscore.
   *
   * @param dn The base DN.
   * @return The container name for the base DN.
   */
  public static String getContainerName(DN dn)
  {
    String normStr = dn.toNormalizedString();
    StringBuilder builder = new StringBuilder(normStr.length());
    for (int i = 0; i < normStr.length(); i++)
    {
      char ch = normStr.charAt(i);
      if (Character.isLetterOrDigit(ch))
      {
        builder.append(ch);
      }
      else
      {
        builder.append('_');
      }
    }
    return builder.toString();
  }
  /**
@@ -641,7 +614,7 @@
  public ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    {
      return ConditionResult.UNDEFINED;
@@ -662,7 +635,8 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN) throws DirectoryException
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    EntryContainer ec;
    if (rootContainer != null)
@@ -685,7 +659,7 @@
    ec.sharedLock.lock();
    try
    {
      long count = ec.getNumSubordinates(entryDN);
      long count = ec.getNumSubordinates(entryDN, subtree);
      if(count == Long.MAX_VALUE)
      {
        // The index entry limit has exceeded and there is no count maintained.
opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -720,19 +720,30 @@
   * Determine the number of subordinate entries for a given entry.
   *
   * @param entryDN The distinguished name of the entry.
   * @param subtree <code>true</code> will include all the entries under the
   *                given entries. <code>false</code> will only return the
   *                number of entries immediately under the given entry.
   * @return The number of subordinate entries for the given entry or -1 if
   *         the entry does not exist.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public long getNumSubordinates(DN entryDN) throws DatabaseException
  public long getNumSubordinates(DN entryDN, boolean subtree)
      throws DatabaseException
  {
    EntryID entryID = dn2id.get(null, entryDN);
    if (entryID != null)
    {
      DatabaseEntry key =
          new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
      EntryIDSet entryIDSet =
          id2children.readKey(key, null, LockMode.DEFAULT);
      EntryIDSet entryIDSet;
      if(!subtree)
      {
        entryIDSet = id2children.readKey(key, null, LockMode.DEFAULT);
      }
      else
      {
        entryIDSet = id2subtree.readKey(key, null, LockMode.DEFAULT);
      }
      long count = entryIDSet.size();
      if(count != Long.MAX_VALUE)
      {
opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -412,7 +412,7 @@
  public ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    {
      return ConditionResult.UNDEFINED;
@@ -433,7 +433,8 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN) throws DirectoryException
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    if (entryDN == null)
    {
@@ -443,7 +444,15 @@
    if (entryDN.equals(taskRootDN))
    {
      // scheduled and recurring parents.
      return 2;
      if(!subtree)
      {
        return 2;
      }
      else
      {
        return taskScheduler.getScheduledTaskCount() +
            taskScheduler.getRecurringTaskCount() + 2;
      }
    }
    else if (entryDN.equals(scheduledTaskParentDN))
    {
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -1163,18 +1163,18 @@
  public ConditionResult hasSubordinates(DN entryDN)
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN);
    if(ret < 0)
    ConfigEntry baseEntry = configEntries.get(entryDN);
    if(baseEntry == null)
    {
      return ConditionResult.UNDEFINED;
    }
    else if(ret == 0)
    else if(baseEntry.hasChildren())
    {
      return ConditionResult.FALSE;
      return ConditionResult.TRUE;
    }
    else
    {
      return ConditionResult.TRUE;
      return ConditionResult.FALSE;
    }
  }
@@ -1184,8 +1184,8 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN)
         throws DirectoryException
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    ConfigEntry baseEntry = configEntries.get(entryDN);
    if (baseEntry == null)
@@ -1193,7 +1193,20 @@
      return -1;
    }
    return baseEntry.getChildren().size();
    if(!subtree)
    {
      return baseEntry.getChildren().size();
    }
    else
    {
      long count = 0;
      for(ConfigEntry child : baseEntry.getChildren().values())
      {
        count += numSubordinates(child.getDN(), true);
        count ++;
      }
      return count;
    }
  }
opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
@@ -119,7 +119,7 @@
    try
    {
      long count = backend.numSubordinates(entry.getDN());
      long count = backend.numSubordinates(entry.getDN(), false);
      if(count >= 0)
      {
        AttributeValue value =
@@ -151,7 +151,7 @@
    try
    {
       return backend.numSubordinates(entry.getDN()) >= 0;
       return backend.numSubordinates(entry.getDN(), false) >= 0;
    }
    catch(DirectoryException de)
    {
@@ -177,7 +177,7 @@
    try
    {
      long count = backend.numSubordinates(entry.getDN());
      long count = backend.numSubordinates(entry.getDN(), false);
      if(count >= 0)
      {
        return Long.parseLong(value.getNormalizedStringValue()) == count;
opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java
@@ -3020,17 +3020,19 @@
      acquireIEContext();
      // The number of entries to be exported is the number of entries under
      // the base DN entry and the base entry itself.
      long entryCount = backend.numSubordinates(baseDN, true) + 1;
      ieContext.exportTarget = target;
      if (initTask != null)
      {
        ieContext.initializeTask = initTask;
        ieContext.initImportExportCounters(backend.getEntryCount());
        ieContext.initImportExportCounters(entryCount);
      }
      // Send start message to the peer
      InitializeTargetMessage initializeMessage = new InitializeTargetMessage(
          baseDN, serverId, ieContext.exportTarget, requestorID,
          backend.getEntryCount());
          baseDN, serverId, ieContext.exportTarget, requestorID, entryCount);
      broker.publish(initializeMessage);
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -952,7 +952,7 @@
   * {@inheritDoc}
   */
  @Override()
  public long numSubordinates(DN entryDN)
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/LDIFBackendTestCase.java
@@ -713,13 +713,16 @@
    assertNotNull(b);
    assertTrue(b instanceof LDIFBackend);
    assertEquals(b.numSubordinates(DN.decode("o=ldif")), 1);
    assertEquals(b.numSubordinates(DN.decode("uid=user.1,ou=People,o=ldif")),
                 0);
    assertEquals(b.numSubordinates(DN.decode("o=ldif"), false), 1);
    assertEquals(b.numSubordinates(DN.decode("o=ldif"), true), 26);
    assertEquals(b.numSubordinates(
        DN.decode("uid=user.1,ou=People,o=ldif"), false), 0);
    assertEquals(b.numSubordinates(
        DN.decode("uid=user.1,ou=People,o=ldif"), true), 0);
    try
    {
      b.numSubordinates(DN.decode("ou=nonexistent,o=ldif"));
      b.numSubordinates(DN.decode("ou=nonexistent,o=ldif"), false);
      fail("Expected an exception when calling numSubordinates on a " +
           "non-existent entry");
    }
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -605,17 +605,23 @@
  public void testNumSubordinates() throws Exception
  {
    DN dn = DN.decode("dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), 1);
    assertEquals(backend.numSubordinates(dn, false), 1);
    assertEquals(backend.numSubordinates(dn, true), 13);
    dn = DN.decode("ou=People,dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), 12);
    assertEquals(backend.numSubordinates(dn, false), 12);
    assertEquals(backend.numSubordinates(dn, true), 12);
    dn = DN.decode("dc=com");
    assertEquals(backend.numSubordinates(dn), -1);
    assertEquals(backend.numSubordinates(dn, false), -1);
    assertEquals(backend.numSubordinates(dn, true), -1);
    dn = DN.decode("dc=test1,dc=com");
    assertEquals(backend.numSubordinates(dn), 2);
    assertEquals(backend.numSubordinates(dn, false), 2);
    assertEquals(backend.numSubordinates(dn, true), 2);
    dn = DN.decode("uid=user.10,ou=People,dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), 0);
    assertEquals(backend.numSubordinates(dn, false), 0);
    assertEquals(backend.numSubordinates(dn, true), 0);
    dn = DN.decode("uid=does not exist,ou=People,dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), -1);
    assertEquals(backend.numSubordinates(dn, false), -1);
    assertEquals(backend.numSubordinates(dn, true), -1);
  }
  @Test(dependsOnMethods = "testAdd")
@@ -1543,19 +1549,25 @@
  public void testNumSubordinatesIndexEntryLimitExceeded() throws Exception
  {
    DN dn = DN.decode("dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), 1);
    assertEquals(backend.numSubordinates(dn, false), 1);
    assertEquals(backend.numSubordinates(dn, true), 14);
    // 1 entry was deleted and 2 added for a total of 13
    dn = DN.decode("ou=People,dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), 13);
    assertEquals(backend.numSubordinates(dn, false), 13);
    assertEquals(backend.numSubordinates(dn, true), 13);
    dn = DN.decode("dc=com");
    assertEquals(backend.numSubordinates(dn), -1);
    assertEquals(backend.numSubordinates(dn, false), -1);
    assertEquals(backend.numSubordinates(dn, true), -1);
    dn = DN.decode("dc=test1,dc=com");
    assertEquals(backend.numSubordinates(dn), 2);
    assertEquals(backend.numSubordinates(dn, false), 2);
    assertEquals(backend.numSubordinates(dn, true), 2);
    dn = DN.decode("uid=user.10,ou=People,dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), 0);
    assertEquals(backend.numSubordinates(dn, false), 0);
    assertEquals(backend.numSubordinates(dn, true), 0);
    dn = DN.decode("uid=does not exist,ou=People,dc=test,dc=com");
    assertEquals(backend.numSubordinates(dn), -1);
    assertEquals(backend.numSubordinates(dn, false), -1);
    assertEquals(backend.numSubordinates(dn, true), -1);
  }