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

abobrov
10.43.2009 d0fa149bb033b08cd0e14c28beb5c1a4d2a7ed06
- add numSubordinates support.
3 files modified
159 ■■■■■ changed files
opends/src/server/org/opends/server/backends/ndb/BackendImpl.java 42 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/ndb/EntryContainer.java 32 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/ndb/OperationContainer.java 85 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/ndb/BackendImpl.java
@@ -1116,11 +1116,11 @@
         throws DirectoryException
  {
    long ret = numSubordinates(entryDN, false);
    if(ret < 0)
    if (ret < 0)
    {
      return ConditionResult.UNDEFINED;
    }
    else if(ret == 0)
    else if (ret == 0)
    {
      return ConditionResult.FALSE;
    }
@@ -1139,8 +1139,42 @@
  public long numSubordinates(DN entryDN, boolean subtree)
      throws DirectoryException
  {
    // NYI.
    return -1;
    EntryContainer ec;
    if (rootContainer != null)
    {
      ec = rootContainer.getEntryContainer(entryDN);
    }
    else
    {
      Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
              message);
    }
    if (ec == null)
    {
      return -1;
    }
    readerBegin();
    ec.sharedLock.lock();
    try
    {
      return ec.getNumSubordinates(entryDN, subtree);
    }
    catch (NdbApiException e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    }
    finally
    {
      ec.sharedLock.unlock();
      readerEnd();
    }
  }
opends/src/server/org/opends/server/backends/ndb/EntryContainer.java
@@ -219,6 +219,38 @@
  }
  /**
   * 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 com.mysql.cluster.ndbj.NdbApiException If an error
   *         occurs in the database.
   */
  public long getNumSubordinates(DN entryDN, boolean subtree)
      throws NdbApiException
  {
    if (baseDN.equals(entryDN)) {
      // Shortcut to avoid scan.
      return getEntryCount() - 1;
    }
    AbstractTransaction txn = new AbstractTransaction(rootContainer);
    try {
      return dn2id.numSubordinates(txn, entryDN, subtree);
    } finally {
      if (txn != null) {
        txn.close();
      }
    }
  }
  /**
   * Processes the specified search in this entryContainer.
   * Matching entries should be provided back to the core server using the
   * <CODE>SearchOperation.returnEntry</CODE> method.
opends/src/server/org/opends/server/backends/ndb/OperationContainer.java
@@ -1556,7 +1556,6 @@
  public boolean hasSubordinates(AbstractTransaction txn, DN dn)
    throws NdbApiException
  {
    // NdbInterpretedOperation op;
    NdbIndexScanOperation op;
    NdbResultSet rs;
@@ -1586,10 +1585,8 @@
        NdbIndexScanOperation.BoundType.BoundLT, "");
    }
    // FIXME: This is extremely inefficient, need NDB/J API
    // like interpretExitLastRow to count result rows node-
    // side without returning them here for check/count.
    // op.interpretExitLastRow();
    // FIXME: Need NDB/J API like native interpretExitLastRow
    // to do this more efficiently without additional hops.
    op.getValue(BackendImpl.EID);
    rs = op.resultData();
@@ -1603,6 +1600,84 @@
  }
  /**
   * Count the number of subordinates for the requested entry DN.
   * @param  txn Abstract transaction to be used for the operation.
   * @param  dn The entry DN.
   * @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 requested
   *         entry or -1 if the entry does not exist.
   * @throws com.mysql.cluster.ndbj.NdbApiException If an error
   * occurs in the database.
   */
  public long numSubordinates(AbstractTransaction txn, DN dn,
    boolean subtree) throws NdbApiException
  {
    long numSubordinates = 0;
    NdbIndexScanOperation op;
    NdbResultSet rs;
    NdbTransaction ndbTxn = txn.getNdbTransaction();
    op = ndbTxn.getSelectIndexScanOperation(
      PRIMARY_INDEX_NAME, name,
      NdbOperation.LockMode.LM_CommittedRead);
    int numComponents = dn.getNumComponents();
    int componentIndex = numComponents - 1;
    for (int i=0; i < numComponents; i++) {
      op.setBoundString(BackendImpl.DN2ID_DN +
        Integer.toString(i),
        NdbIndexScanOperation.BoundType.BoundEQ,
        dn.getRDN(componentIndex).toNormalizedString());
      componentIndex--;
    }
    // FIXME: Need multi range bound here to optimize in
    // NOT subtree case which would prevent subtree walk
    // when it is not needed. need NDB/J API to do that.
    // native API: NdbIndexScanOperation::end_of_bound()
    if (dn.getNumComponents() < BackendImpl.DN2ID_DN_NC) {
      String nextRDNColumn =
        BackendImpl.DN2ID_DN + Integer.toString(numComponents);
      op.setBoundString(nextRDNColumn,
        NdbIndexScanOperation.BoundType.BoundLT, "");
    }
    // FIXME: Need NDB/J API like native interpretExitLastRow
    // to do this more efficiently without additional hops.
    op.getValue(BackendImpl.EID);
    String subtreeColumn = BackendImpl.DN2ID_DN +
      Integer.toString(dn.getNumComponents() + 1);
    if (!subtree &&
        (dn.getNumComponents() < BackendImpl.DN2ID_DN_NC))
    {
      op.getValue(subtreeColumn);
    }
    rs = op.resultData();
    ndbTxn.execute(ExecType.NoCommit, AbortOption.AO_IgnoreError, true);
    while (rs.next()) {
      if (!subtree &&
          (dn.getNumComponents() < BackendImpl.DN2ID_DN_NC))
      {
        String columnValue = rs.getString(subtreeColumn);
        if ((columnValue != null) && (columnValue.length() > 0))
        {
          continue;
        }
      }
      numSubordinates++;
    }
    return numSubordinates;
  }
  /**
   * Get a new instance of the Search Cursor object.
   * @param txn Abstract Transaction to be used for the operation.
   * @param baseDN Search Cursor base DN.