From 4ef568921c23735eb9a1eafd1f048e74762c1cf7 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 22 Dec 2014 23:13:32 +0000
Subject: [PATCH] OPENDJ-1710: NPE performing deletes and potentially other indexed updates against Persistit backend

---
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DN2URI.java         |   17 +----
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/Index.java          |    7 +-
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java |  133 ++++++++++++++------------------------------
 3 files changed, 50 insertions(+), 107 deletions(-)

diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DN2URI.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DN2URI.java
index 34d8cc5..d25e7ec 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DN2URI.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DN2URI.java
@@ -580,7 +580,6 @@
     suffix.append((byte) 0x00);
     end.append((byte) 0x01);
 
-    ByteSequence startKey = suffix;
     try
     {
       final Cursor cursor = txn.openCursor(treeName);
@@ -588,23 +587,15 @@
       {
         // Initialize the cursor very close to the starting value then
         // step forward until we pass the ending value.
-        boolean success = cursor.positionToKey(startKey);
-        while (success)
+        boolean success = cursor.positionToKey(suffix);
+        while (success && cursor.getKey().compareTo(end) < 0)
         {
-          ByteString key = cursor.getKey();
-          int cmp = ByteSequence.COMPARATOR.compare(key, end);
-          if (cmp >= 0)
-          {
-            // We have gone past the ending value.
-            break;
-          }
-
           // We have found a subordinate referral.
-          DN dn = JebFormat.dnFromDNKey(key, entryContainer.getBaseDN());
+          DN dn = JebFormat.dnFromDNKey(cursor.getKey(), entryContainer.getBaseDN());
 
           // Make sure the referral is within scope.
           if (searchOp.getScope() == SearchScope.SINGLE_LEVEL
-              && JebFormat.findDNKeyParent(key) != baseDN.length())
+              && JebFormat.findDNKeyParent(cursor.getKey()) != baseDN.length())
           {
             continue;
           }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
index 07fcc8d..fe8858c 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
@@ -1224,8 +1224,6 @@
       begin = suffix;
     }
 
-    ByteSequence startKey = begin;
-
     int lookthroughCount = 0;
     int lookthroughLimit = searchOperation.getClientConnection().getLookthroughLimit();
 
@@ -1235,30 +1233,21 @@
       try
       {
         // Initialize the cursor very close to the starting value.
-        boolean success = cursor.positionToKeyOrNext(startKey);
+        boolean success = cursor.positionToKeyOrNext(begin);
 
         // Step forward until we pass the ending value.
-        while (success)
+        while (success && cursor.getKey().compareTo(end) < 0)
         {
-          if(lookthroughLimit > 0 && lookthroughCount > lookthroughLimit)
+          if (lookthroughLimit > 0 && lookthroughCount > lookthroughLimit)
           {
-            //Lookthrough limit exceeded
+            // Lookthrough limit exceeded
             searchOperation.setResultCode(ResultCode.ADMIN_LIMIT_EXCEEDED);
-            searchOperation.appendErrorMessage(
-                NOTE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED.get(lookthroughLimit));
+            searchOperation.appendErrorMessage(NOTE_JEB_LOOKTHROUGH_LIMIT_EXCEEDED.get(lookthroughLimit));
             return;
           }
-          int cmp = ByteSequence.COMPARATOR.compare(cursor.getKey(), end);
-          if (cmp >= 0)
-          {
-            // We have gone past the ending value.
-            break;
-          }
 
           // We have found a subordinate entry.
-
           EntryID entryID = new EntryID(cursor.getValue());
-
           boolean isInScope =
               searchScope != SearchScope.SINGLE_LEVEL
                   // Check if this entry is an immediate child.
@@ -1728,31 +1717,13 @@
 
             int subordinateEntriesDeleted = 0;
 
-            ByteSequence startKey = suffix;
-
             Cursor cursor = dn2id.openCursor(txn);
             try
             {
-              // Initialize the cursor very close to the starting value.
-              boolean success = cursor.positionToKeyOrNext(startKey);
-
-              // Step forward until the key is greater than the starting value.
-              while (success
-                  && ByteSequence.COMPARATOR.compare(cursor.getKey(), suffix) <= 0)
-              {
-                success = cursor.next();
-              }
-
               // Step forward until we pass the ending value.
-              while (success)
+              boolean success = cursor.positionToKeyOrNext(suffix);
+              while (success && cursor.getKey().compareTo(end) < 0)
               {
-                int cmp = ByteSequence.COMPARATOR.compare(cursor.getKey(), end);
-                if (cmp >= 0)
-                {
-                  // We have gone past the ending value.
-                  break;
-                }
-
                 // We have found a subordinate entry.
                 if (!isSubtreeDelete)
                 {
@@ -2030,53 +2001,52 @@
   private Entry getEntry0(ReadableStorage txn, final DN entryDN) throws StorageRuntimeException, DirectoryException
   {
     final EntryCache<?> entryCache = DirectoryServer.getEntryCache();
-    Entry entry = null;
 
     // Try the entry cache first.
     if (entryCache != null)
     {
-      entry = entryCache.getEntry(entryDN);
+      final Entry entry = entryCache.getEntry(entryDN);
+      if (entry != null)
+      {
+        return entry;
+      }
     }
 
-    if (entry == null)
+    try
     {
-      try
+      // Read dn2id.
+      EntryID entryID = dn2id.get(txn, entryDN, false);
+      if (entryID == null)
       {
-        // Read dn2id.
-        EntryID entryID = dn2id.get(txn, entryDN, false);
-        if (entryID == null)
-        {
-          // The entryDN does not exist.
-          // Check for referral entries above the target entry.
-          dn2uri.targetEntryReferrals(txn, entryDN, null);
-          return null;
-        }
-
-        // Read id2entry.
-        Entry entry2 = id2entry.get(txn, entryID, false);
-        if (entry2 == null)
-        {
-          // The entryID does not exist.
-          throw new DirectoryException(getServerErrorResultCode(), ERR_JEB_MISSING_ID2ENTRY_RECORD.get(entryID));
-        }
-
-        // 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.
-        if (entryCache != null)
-        {
-          entryCache.putEntryIfAbsent(entry2, backend, entryID.longValue());
-        }
-        return entry2;
+        // The entryDN does not exist.
+        // Check for referral entries above the target entry.
+        dn2uri.targetEntryReferrals(txn, entryDN, null);
+        return null;
       }
-      catch (Exception e)
+
+      // Read id2entry.
+      final Entry entry = id2entry.get(txn, entryID, false);
+      if (entry == null)
       {
-        // it is not very clean to specify twice the same exception but it saves me some code for now
-        throwAllowedExceptionTypes(e, DirectoryException.class, DirectoryException.class);
+        // The entryID does not exist.
+        throw new DirectoryException(getServerErrorResultCode(), ERR_JEB_MISSING_ID2ENTRY_RECORD.get(entryID));
       }
+
+      // 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.
+      if (entryCache != null)
+      {
+        entryCache.putEntryIfAbsent(entry, backend, entryID.longValue());
+      }
+      return entry;
     }
-
-    return entry;
+    catch (Exception e)
+    {
+      // it is not very clean to specify twice the same exception but it saves me some code for now
+      throwAllowedExceptionTypes(e, DirectoryException.class, DirectoryException.class);
+      return null; // unreachable
+    }
   }
 
   /**
@@ -2337,32 +2307,15 @@
             suffix.append((byte) 0x00);
             end.append((byte) 0x01);
 
-            ByteSequence startKey = suffix;
-
             Cursor cursor = txn.openCursor(dn2id.getName());
             try
             {
-              // Initialize the cursor very close to the starting value.
-              boolean success = cursor.positionToKeyOrNext(startKey);
-
-              // Step forward until the key is greater than the starting value.
-              while (success && ByteSequence.COMPARATOR.compare(cursor.getKey(), suffix) <= 0)
-              {
-                success = cursor.next();
-              }
 
               // Step forward until we pass the ending value.
-              while (success)
+              boolean success = cursor.positionToKeyOrNext(suffix);
+              while (success && cursor.getKey().compareTo(end) < 0)
               {
-                int cmp = ByteSequence.COMPARATOR.compare(cursor.getKey(), end);
-                if (cmp >= 0)
-                {
-                  // We have gone past the ending value.
-                  break;
-                }
-
                 // We have found a subordinate entry.
-
                 EntryID oldID = new EntryID(cursor.getValue());
                 Entry oldEntry = id2entry.get(txn, oldID, false);
 
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/Index.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/Index.java
index 4f1ff94..6c8e09a 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/Index.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/Index.java
@@ -519,9 +519,7 @@
           success = cursor.positionToKeyOrNext(lower);
 
           // Advance past the lower bound if necessary.
-          if (success
-              && !lowerIncluded
-              && ByteSequence.COMPARATOR.compare(cursor.getKey(), lower) == 0)
+          if (success && !lowerIncluded && cursor.getKey().equals(lower))
           {
             // Do not include the lower value.
             success = cursor.next();
@@ -544,12 +542,13 @@
           // Check against the upper bound if necessary
           if (upper.length() > 0)
           {
-            int cmp = ByteSequence.COMPARATOR.compare(cursor.getKey(), upper);
+            int cmp = cursor.getKey().compareTo(upper);
             if (cmp > 0 || (cmp == 0 && !upperIncluded))
             {
               break;
             }
           }
+
           EntryIDSet list = new EntryIDSet(cursor.getKey(), cursor.getValue());
           if (!list.isDefined())
           {

--
Gitblit v1.10.0