From da62427f3da608acc65cea059cff0232d7980727 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 04 Dec 2014 17:02:39 +0000
Subject: [PATCH] OPENDJ-1602 (CR-5566) New pluggable storage based backend

---
 opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java |  150 +++++-------------------
 opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java         |  101 ++++++----------
 opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java  |   20 +++
 opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java       |   37 +----
 4 files changed, 105 insertions(+), 203 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 063e5b7..b89d0f7 100644
--- a/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -43,7 +43,7 @@
 import org.opends.server.api.AccessControlHandler;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConfigHandler;
-import org.opends.server.backends.jeb.EntryContainer;
+import org.opends.server.backends.pluggable.SuffixContainer;
 import org.opends.server.controls.GetEffectiveRightsRequestControl;
 import org.opends.server.core.*;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -64,8 +64,7 @@
 import static org.opends.server.util.StaticUtils.*;
 
 /**
- * The AciHandler class performs the main processing for the dseecompat
- * package.
+ * The AciHandler class performs the main processing for the dseecompat package.
  */
 public final class AciHandler extends
     AccessControlHandler<DseeCompatAccessControlHandlerCfg>
@@ -80,8 +79,7 @@
    * String used to indicate that the evaluating ACI had a all user
    * attributes targetattr match (targetattr="*").
    */
-  public static final String ALL_USER_ATTRS_MATCHED =
-      "allUserAttrsMatched";
+  public static final String ALL_USER_ATTRS_MATCHED = "allUserAttrsMatched";
 
   /**
    * String used to save the original authorization entry in an
@@ -89,25 +87,16 @@
    */
   public static final String ORIG_AUTH_ENTRY = "origAuthorizationEntry";
 
-  /**
-   * Attribute type corresponding to "aci" attribute.
-   */
+  /** Attribute type corresponding to "aci" attribute. */
   static AttributeType aciType;
 
-  /**
-   * Attribute type corresponding to global "ds-cfg-global-aci"
-   * attribute.
-   */
+  /** Attribute type corresponding to global "ds-cfg-global-aci" attribute. */
   static AttributeType globalAciType;
 
-  /**
-   * Attribute type corresponding to "debugsearchindex" attribute.
-   */
+  /** Attribute type corresponding to "debugsearchindex" attribute. */
   private static AttributeType debugSearchIndex;
 
-  /**
-   * DN corresponding to "debugsearchindex" attribute type.
-   */
+  /** DN corresponding to "debugsearchindex" attribute type. */
   private static DN debugSearchIndexDN;
 
   /**
@@ -132,7 +121,7 @@
   {
     aciType = getAttributeType("aci");
     globalAciType = getAttributeType(ATTR_AUTHZ_GLOBAL_ACI);
-    debugSearchIndex = getAttributeType(EntryContainer.ATTR_DEBUG_SEARCH_INDEX);
+    debugSearchIndex = getAttributeType(SuffixContainer.ATTR_DEBUG_SEARCH_INDEX);
     refAttrType = getAttributeType(ATTR_REFERRAL_URL);
 
     try
@@ -157,35 +146,23 @@
 
 
 
-  /**
-   * The list that holds that ACIs keyed by the DN of the entry holding
-   * the ACI.
-   */
+  /** The list that holds that ACIs keyed by the DN of the entry holding the ACI. */
   private AciList aciList;
 
   /**
    * The listener that handles ACI changes caused by LDAP operations,
-   * ACI decode failure alert logging and backend initialization ACI
-   * list adjustment.
+   * ACI decode failure alert logging and backend initialization ACI list adjustment.
    */
   private AciListenerManager aciListenerMgr;
 
-
-
-  /**
-   * Creates a new DSEE-compatible access control handler.
-   */
+  /** Creates a new DSEE-compatible access control handler. */
   public AciHandler()
   {
     // No implementation required. All initialization should be done in
     // the intializeAccessControlHandler method.
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public void filterEntry(Operation operation,
       SearchResultEntry unfilteredEntry, SearchResultEntry filteredEntry)
@@ -211,12 +188,8 @@
     }
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
+  /** {@inheritDoc} */
+  @Override
   public void finalizeAccessControlHandler()
   {
     aciListenerMgr.finalizeListenerManager();
@@ -224,12 +197,8 @@
     DirectoryServer.deregisterSupportedControl(OID_GET_EFFECTIVE_RIGHTS);
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
+  /** {@inheritDoc} */
+  @Override
   public void initializeAccessControlHandler(
       DseeCompatAccessControlHandlerCfg configuration)
       throws ConfigException, InitializationException
@@ -243,11 +212,7 @@
     DirectoryServer.registerSupportedControl(OID_GET_EFFECTIVE_RIGHTS);
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(DN entryDN, Operation op, Control control)
       throws DirectoryException
@@ -286,11 +251,7 @@
     return true;
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(ExtendedOperation operation)
   {
@@ -305,33 +266,19 @@
     return accessAllowed(container);
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(LocalBackendAddOperation operation)
       throws DirectoryException
   {
-    AciContainer container =
-        new AciLDAPOperationContainer(operation, ACI_ADD);
-    if (!isAllowed(container, operation))
-    {
-      return false;
-    }
-
-    // LDAP add needs a verify ACI syntax step in case any
-    // "aci" attribute types are being added.
-    return verifySyntax(operation.getEntryToAdd(), operation, container
-        .getClientDN());
+    AciContainer container = new AciLDAPOperationContainer(operation, ACI_ADD);
+    return isAllowed(container, operation)
+        // LDAP add needs a verify ACI syntax step in case any
+        // "aci" attribute types are being added.
+        && verifySyntax(operation.getEntryToAdd(), operation, container.getClientDN());
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(BindOperation bindOperation)
   {
@@ -428,9 +375,8 @@
     // original entry DN has export access.
     if (rdnChangesAllowed && newSuperiorDN != null)
     {
-      AciContainer container =
-          new AciLDAPOperationContainer(operation, ACI_EXPORT, operation
-              .getOriginalEntry());
+      AciContainer container = new AciLDAPOperationContainer(
+          operation, ACI_EXPORT, operation.getOriginalEntry());
       if (!oldRDN.equals(newRDN))
       {
         // The RDNs are not equal, skip the proxy check since it was
@@ -442,11 +388,7 @@
     return rdnChangesAllowed;
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(LocalBackendModifyOperation operation)
       throws DirectoryException
@@ -455,11 +397,7 @@
     return aciCheckMods(container, operation, skipAccessCheck(operation));
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(SearchOperation searchOperation)
   {
@@ -467,11 +405,7 @@
     return true;
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean isAllowed(Operation operation, Entry entry,
       SearchFilter filter) throws DirectoryException
@@ -486,14 +420,9 @@
     return testFilter(container, filter);
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
-  public boolean mayProxy(Entry proxyUser, Entry proxiedUser,
-      Operation op)
+  public boolean mayProxy(Entry proxyUser, Entry proxiedUser, Operation op)
   {
     if (skipAccessCheck(proxyUser))
     {
@@ -508,14 +437,9 @@
     return accessAllowedEntry(container);
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
-  public boolean maySend(DN dn, Operation operation,
-      SearchResultReference reference)
+  public boolean maySend(DN dn, Operation operation, SearchResultReference reference)
   {
     if (skipAccessCheck(operation))
     {
@@ -541,11 +465,7 @@
     return accessAllowed(container);
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public boolean maySend(Operation operation, SearchResultEntry entry)
   {
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 1997c79..e5058a5 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -90,8 +90,6 @@
   private static final String REFERRAL_DATABASE_NAME = REFERRAL_INDEX_NAME;
   /** The name of the state database. */
   private static final String STATE_DATABASE_NAME = STATE_INDEX_NAME;
-  /** The attribute used to return a search index debug string to the client. */
-  public static final String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
 
   /** The attribute index configuration manager. */
   private final AttributeJEIndexCfgManager attributeJEIndexCfgManager;
@@ -769,8 +767,7 @@
       searchOperation.setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
       return;
     }
-    VLVRequestControl vlvRequest = searchOperation
-    .getRequestControl(VLVRequestControl.DECODER);
+    VLVRequestControl vlvRequest = searchOperation.getRequestControl(VLVRequestControl.DECODER);
 
     if (vlvRequest != null && pageRequest != null)
     {
@@ -889,8 +886,7 @@
         {
           LocalizableMessage message = ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(aBaseDN);
           DN matchedDN = getMatchedDN(aBaseDN);
-          throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
-              message, matchedDN, null);
+          throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, matchedDN, null);
         }
         DatabaseEntry baseIDData = baseID.getDatabaseEntry();
 
@@ -940,11 +936,11 @@
             else
             {
               /*
-                There is no sort key associated with the sort control. Since it
-                came here it means that the criticality is false so let the
-                server return all search results unsorted and include the
-                sortKeyResponseControl in the searchResultDone message.
-              */
+               * There is no sort key associated with the sort control. Since it
+               * came here it means that the criticality is false so let the
+               * server return all search results unsorted and include the
+               * sortKeyResponseControl in the searchResultDone message.
+               */
               searchOperation.addResponseControl(new ServerSideSortResponseControl(NO_SUCH_ATTRIBUTE, null));
             }
           }
@@ -1018,8 +1014,7 @@
         if (sortRequest.isCritical())
         {
           LocalizableMessage message = ERR_JEB_SEARCH_CANNOT_SORT_UNINDEXED.get();
-          throw new DirectoryException(
-              ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message);
+          throw new DirectoryException(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, message);
         }
       }
 
@@ -1048,7 +1043,6 @@
   private void searchNotIndexed(SearchOperation searchOperation, PagedResultsControl pageRequest)
       throws DirectoryException, CanceledOperationException
   {
-    EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     DN aBaseDN = searchOperation.getBaseDN();
     SearchScope searchScope = searchOperation.getScope();
     boolean manageDsaIT = isManageDsaITOperation(searchOperation);
@@ -1171,20 +1165,8 @@
                   || findDNKeyParent(key.getData(), 0, key.getSize()) == baseDNKey.length;
           if (isInScope)
           {
-            // Try the entry cache first.
-            final Entry cacheEntry = entryCache.getEntry(backend, entryID.longValue());
-
-            final Entry entry;
-            if (cacheEntry != null)
-            {
-              entry = cacheEntry;
-            }
-            else
-            {
-              entry = id2entry.get(null, entryID, LockMode.DEFAULT);
-            }
-
             // Process the candidate entry.
+            final Entry entry = getEntry(entryID);
             if (entry != null)
             {
               lookthroughCount++;
@@ -1238,6 +1220,28 @@
     }
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public Entry getEntry(EntryID entryID) throws DirectoryException
+  {
+    // Try the entry cache first.
+    final EntryCache entryCache = getEntryCache();
+    final Entry cacheEntry = entryCache.getEntry(backend, entryID.longValue());
+    if (cacheEntry != null)
+    {
+      return cacheEntry;
+    }
+
+    final Entry entry = id2entry.get(null, entryID, LockMode.DEFAULT);
+    if (entry != null)
+    {
+      // Put the entry in the cache making sure not to overwrite a newer copy
+      // that may have been inserted since the time we read the cache.
+      entryCache.putEntryIfAbsent(entry, backend, entryID.longValue());
+    }
+    return entry;
+  }
+
   /**
    * We were able to obtain a set of candidate entry IDs for the
    * search from the indexes.
@@ -1266,7 +1270,6 @@
       PagedResultsControl pageRequest)
   throws DirectoryException, CanceledOperationException
   {
-    EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     SearchScope searchScope = searchOperation.getScope();
     DN aBaseDN = searchOperation.getBaseDN();
     boolean manageDsaIT = isManageDsaITOperation(searchOperation);
@@ -1315,49 +1318,27 @@
       {
         final EntryID id = it.next();
 
-        // Try the entry cache first.
         Entry entry;
-        Entry cacheEntry = entryCache.getEntry(backend, id.longValue());
-        if (cacheEntry == null)
+        try
         {
-          // Fetch the candidate entry from the database.
-          try
-          {
-            entry = id2entry.get(null, id, LockMode.DEFAULT);
-          }
-          catch (Exception e)
-          {
-            logger.traceException(e);
-            continue;
-          }
+          entry = getEntry(id);
         }
-        else
+        catch (Exception e)
         {
-          entry = cacheEntry;
+          logger.traceException(e);
+          continue;
         }
 
         // Process the candidate entry.
         if (entry != null)
         {
-          boolean isInScope = isInScope(candidatesAreInScope, searchScope, aBaseDN, entry);
-
-          // Put this entry in the cache if it did not come from the cache.
-          if (cacheEntry == null)
-          {
-            // Put the entry in the cache making sure not to overwrite
-            // a newer copy that may have been inserted since the time
-            // we read the cache.
-            entryCache.putEntryIfAbsent(entry, backend, id.longValue());
-          }
-
           // Filter the entry if it is in scope.
-          if (isInScope
+          if (isInScope(candidatesAreInScope, searchScope, aBaseDN, entry)
               && (manageDsaIT || entry.getReferralURLs() == null)
               && searchOperation.getFilter().matchesEntry(entry))
           {
-            if (pageRequest != null &&
-                searchOperation.getEntriesSent() ==
-                pageRequest.getSize())
+            if (pageRequest != null
+                && searchOperation.getEntriesSent() == pageRequest.getSize())
             {
               // The current page is full.
               // Set the cookie to remember where we were.
@@ -1384,8 +1365,8 @@
     // Before we return success from the search we must ensure the base entry
     // exists. However, if we have returned at least one entry or subordinate
     // reference it implies the base does exist, so we can omit the check.
-    if (searchOperation.getEntriesSent() == 0 &&
-        searchOperation.getReferencesSent() == 0)
+    if (searchOperation.getEntriesSent() == 0
+        && searchOperation.getReferencesSent() == 0)
     {
       // Fetch the base entry if it exists.
       Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope);
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
index 2d5a7ec..fb127d6 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryIDSetSorter.java
@@ -35,6 +35,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
+import org.opends.server.backends.pluggable.SuffixContainer;
 import org.opends.server.controls.VLVRequestControl;
 import org.opends.server.controls.VLVResponseControl;
 import org.opends.server.core.DirectoryServer;
@@ -42,8 +43,6 @@
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.types.*;
 
-import com.sleepycat.je.LockMode;
-
 import static org.opends.messages.JebMessages.*;
 import static org.opends.server.util.StaticUtils.*;
 
@@ -57,8 +56,7 @@
    * Creates a new entry ID set which is a sorted representation of the provided
    * set using the given sort order.
    *
-   * @param  entryContainer   The entry container with which the ID list is
-   *                          associated.
+   * @param  suffixContainer  The suffix container with which the ID list is associated.
    * @param  entryIDSet       The entry ID set to be sorted.
    * @param  searchOperation  The search operation being processed.
    * @param  sortOrder        The sort order to use for the entry ID set.
@@ -70,7 +68,7 @@
    *
    * @throws  DirectoryException  If an error occurs while performing the sort.
    */
-  public static EntryIDSet sort(EntryContainer entryContainer,
+  public static EntryIDSet sort(SuffixContainer suffixContainer,
                                 EntryIDSet entryIDSet,
                                 SearchOperation searchOperation,
                                 SortOrder sortOrder,
@@ -82,7 +80,6 @@
       return new EntryIDSet();
     }
 
-    ID2Entry id2Entry = entryContainer.getID2Entry();
     DN baseDN = searchOperation.getBaseDN();
     SearchScope scope = searchOperation.getScope();
     SearchFilter filter = searchOperation.getFilter();
@@ -92,15 +89,11 @@
     {
       try
       {
-        Entry e = id2Entry.get(null, id, LockMode.DEFAULT);
-
-        if ((! e.matchesBaseAndScope(baseDN, scope)) ||
-            (! filter.matchesEntry(e)))
+        Entry e = suffixContainer.getEntry(id);
+        if (e.matchesBaseAndScope(baseDN, scope) && filter.matchesEntry(e))
         {
-          continue;
+          sortMap.put(new SortValues(id, e, sortOrder), id);
         }
-
-        sortMap.put(new SortValues(id, e, sortOrder), id);
       }
       catch (Exception e)
       {
@@ -111,8 +104,7 @@
 
 
     // See if there is a VLV request to further pare down the set of results,
-    // and if there is where it should be processed by offset or assertion
-    // value.
+    // and if there is where it should be processed by offset or assertion value.
     long[] sortedIDs;
     if (vlvRequest != null)
     {
@@ -124,8 +116,7 @@
         int targetOffset = vlvRequest.getOffset();
         if (targetOffset < 0)
         {
-          // The client specified a negative target offset.  This should never
-          // be allowed.
+          // The client specified a negative target offset.  This should never be allowed.
           searchOperation.addResponseControl(
                new VLVResponseControl(targetOffset, sortMap.size(),
                                       LDAPResultCode.OFFSET_RANGE_ERROR));
@@ -167,10 +158,8 @@
 
         int treePos = 0;
         int arrayPos = 0;
-        Iterator<EntryID> idIterator = sortMap.values().iterator();
-        while (idIterator.hasNext())
+        for (EntryID id : sortMap.values())
         {
-          EntryID id = idIterator.next();
           if (treePos++ < startPos)
           {
             continue;
@@ -206,11 +195,8 @@
         int includedAfterCount  = 0;
         int listSize            = 0;
         LinkedList<EntryID> idList = new LinkedList<EntryID>();
-        Iterator<Map.Entry<SortValues,EntryID>> mapIterator =
-             sortMap.entrySet().iterator();
-        while (mapIterator.hasNext())
+        for (Map.Entry<SortValues, EntryID> entry : sortMap.entrySet())
         {
-          Map.Entry<SortValues,EntryID> entry = mapIterator.next();
           SortValues sortValues = entry.getKey();
           EntryID id = entry.getValue();
 
@@ -226,7 +212,7 @@
           }
           else
           {
-            targetFound = (sortValues.compareTo(assertionValue) >= 0);
+            targetFound = sortValues.compareTo(assertionValue) >= 0;
             targetOffset++;
 
             if (targetFound)
@@ -283,4 +269,3 @@
     return new EntryIDSet(sortedIDs, 0, sortedIDs.length);
   }
 }
-
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
index a90682a..d566e57 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
@@ -26,7 +26,10 @@
 
 import java.io.Closeable;
 
+import org.opends.server.backends.jeb.EntryID;
 import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
 
 /**
  * Container for a whole suffix environment which stores all entries from the
@@ -50,12 +53,13 @@
   String ID2ENTRY_INDEX_NAME = "id2entry";
   /**
    * The name of the index associating an entry id to the entry id set of all
-   * its children.
+   * its children, i.e. its immediate children.
    */
   String ID2CHILDREN_INDEX_NAME = "id2children";
   /**
    * The name of the index associating an entry id to the entry id set of all
-   * its subordinates.
+   * its subordinates, i.e. the children, grand-children, grand-grand-children,
+   * ....
    */
   String ID2SUBTREE_INDEX_NAME = "id2subtree";
   /** The name of the index associating normalized DNs to normalized URIs. */
@@ -65,6 +69,8 @@
    * does the index needs to be rebuilt ?
    */
   String STATE_INDEX_NAME = "state";
+  /** The attribute used to return a search index debug string to the client. */
+  String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
 
   /**
    * Returns the baseDN that this suffix container is responsible for.
@@ -81,4 +87,14 @@
    */
   long getEntryCount();
 
+  /**
+   * Returns the entry corresponding to the provided entryID.
+   *
+   * @param entryID
+   *          the id of the entry to retrieve
+   * @return the entry corresponding to the provided entryID
+   * @throws DirectoryException
+   *           If an error occurs retrieving the entry
+   */
+  Entry getEntry(EntryID entryID) throws DirectoryException;
 }

--
Gitblit v1.10.0