From 4942a89087d560696123c5de7d87ee99c2210c9d Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Tue, 22 Sep 2009 20:56:23 +0000
Subject: [PATCH] Fix for issue 4117: Reordered the access to dn2id such that all moved DNs are removed sequentially then added back. Also fixed a case where an error caused by a corrupted index does not result in the index being put into the untrusted state.

---
 opends/src/server/org/opends/server/backends/jeb/EntryContainer.java |  183 ++++++++++++++++++++++++---------------------
 1 files changed, 99 insertions(+), 84 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 0051462..b9f65dc 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -2527,9 +2527,13 @@
         }
       }
 
+      MovedEntry head = new MovedEntry(null, null, false);
+      MovedEntry current = head;
       // Move or rename the apex entry.
-      renameApexEntry(txn, buffer, oldSuperiorDN, newSuperiorDN, oldApexID,
-          newApexID, oldApexEntry, entry,isApexEntryMoved, modifyDNOperation);
+      removeApexEntry(txn, buffer, oldSuperiorDN, oldApexID,
+          newApexID, oldApexEntry, entry,isApexEntryMoved, modifyDNOperation,
+          current);
+      current = current.next;
 
       /*
        * We will iterate forwards through a range of the dn2id keys to
@@ -2606,9 +2610,10 @@
           }
 
           // Move this entry.
-          renameSubordinateEntry(txn, buffer, oldSuperiorDN, newSuperiorDN,
+          removeSubordinateEntry(txn, buffer, oldSuperiorDN,
               oldID, newID, oldEntry, newDN, isApexEntryMoved,
-              modifyDNOperation);
+              modifyDNOperation, current);
+          current = current.next;
 
           if(modifyDNOperation != null)
           {
@@ -2624,6 +2629,17 @@
         cursor.close();
       }
 
+      // Set current to the first moved entry and null out the head. This will
+      // allow processed moved entries to be GCed.
+      current = head.next;
+      head = null;
+      while(current != null)
+      {
+        addRenamedEntry(txn, buffer, current.entryID, current.entry,
+                        isApexEntryMoved, current.renumbered,
+                        modifyDNOperation);
+        current = current.next;
+      }
       buffer.flush(txn);
 
       if(modifyDNOperation != null)
@@ -2665,38 +2681,96 @@
     }
   }
 
-  private void renameApexEntry(Transaction txn, IndexBuffer buffer,
-      DN oldSuperiorDN, DN newSuperiorDN,
+  /**
+   * Represents an renamed entry that was deleted from JE but yet to be added
+   * back.
+   */
+  private static class MovedEntry
+  {
+    EntryID entryID;
+    Entry entry;
+    MovedEntry next;
+    boolean renumbered;
+
+    private MovedEntry(EntryID entryID, Entry entry, boolean renumbered)
+    {
+      this.entryID = entryID;
+      this.entry = entry;
+      this.renumbered = renumbered;
+    }
+  }
+
+  private void addRenamedEntry(Transaction txn, IndexBuffer buffer,
+                           EntryID newID,
+                           Entry newEntry,
+                           boolean isApexEntryMoved,
+                           boolean renumbered,
+                           ModifyDNOperation modifyDNOperation)
+      throws DirectoryException, DatabaseException
+  {
+    if (!dn2id.insert(txn, newEntry.getDN(), newID))
+    {
+      Message message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get(
+          newEntry.getDN().toString());
+      throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
+                                   message);
+    }
+    id2entry.put(txn, newID, newEntry);
+    dn2uri.addEntry(txn, newEntry);
+
+    if (renumbered || modifyDNOperation == null)
+    {
+      // Reindex the entry with the new ID.
+      indexInsertEntry(buffer, newEntry, newID);
+    }
+
+    // Add the new ID to id2children and id2subtree of new apex parent entry.
+    if(isApexEntryMoved)
+    {
+      EntryID parentID;
+      byte[] parentIDKeyBytes;
+      boolean isParent = true;
+      for (DN dn = getParentWithinBase(newEntry.getDN()); dn != null;
+           dn = getParentWithinBase(dn))
+      {
+        parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
+        parentIDKeyBytes =
+            JebFormat.entryIDToDatabase(parentID.longValue());
+        if(isParent)
+        {
+          id2children.insertID(buffer, parentIDKeyBytes, newID);
+          isParent = false;
+        }
+        id2subtree.insertID(buffer, parentIDKeyBytes, newID);
+      }
+    }
+  }
+
+  private void removeApexEntry(Transaction txn, IndexBuffer buffer,
+      DN oldSuperiorDN,
       EntryID oldID, EntryID newID,
       Entry oldEntry, Entry newEntry,
       boolean isApexEntryMoved,
-      ModifyDNOperation modifyDNOperation)
+      ModifyDNOperation modifyDNOperation,
+      MovedEntry tail)
   throws DirectoryException, DatabaseException
   {
     DN oldDN = oldEntry.getDN();
-    DN newDN = newEntry.getDN();
 
     // Remove the old DN from dn2id.
     dn2id.remove(txn, oldDN);
 
-    // Put the new DN in dn2id.
-    if (!dn2id.insert(txn, newDN, newID))
-    {
-      Message message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get(newDN.toString());
-      throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
-          message);
-    }
-
     // Remove old ID from id2entry and put the new entry
     // (old entry with new DN) in id2entry.
     if (!newID.equals(oldID))
     {
       id2entry.remove(txn, oldID);
     }
-    id2entry.put(txn, newID, newEntry);
 
     // Update any referral records.
-    dn2uri.replaceEntry(txn, oldEntry, newEntry);
+    dn2uri.deleteEntry(txn, oldEntry);
+
+    tail.next = new MovedEntry(newID, newEntry, !newID.equals(oldID));
 
     // Remove the old ID from id2children and id2subtree of
     // the old apex parent entry.
@@ -2729,7 +2803,6 @@
 
       // Reindex the entry with the new ID.
       indexRemoveEntry(buffer, oldEntry, oldID);
-      indexInsertEntry(buffer, newEntry, newID);
     }
     else
     {
@@ -2738,26 +2811,6 @@
           modifyDNOperation.getModifications());
     }
 
-    // Add the new ID to id2children and id2subtree of new apex parent entry.
-    if(newSuperiorDN != null && isApexEntryMoved)
-    {
-      EntryID parentID;
-      byte[] parentIDKeyBytes;
-      boolean isParent = true;
-      for (DN dn = newSuperiorDN; dn != null; dn = getParentWithinBase(dn))
-      {
-        parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
-        parentIDKeyBytes =
-          JebFormat.entryIDToDatabase(parentID.longValue());
-        if(isParent)
-        {
-          id2children.insertID(buffer, parentIDKeyBytes, newID);
-          isParent = false;
-        }
-        id2subtree.insertID(buffer, parentIDKeyBytes, newID);
-      }
-    }
-
     // Remove the entry from the entry cache.
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     if (entryCache != null)
@@ -2766,12 +2819,13 @@
     }
   }
 
-  private void renameSubordinateEntry(Transaction txn, IndexBuffer buffer,
-      DN oldSuperiorDN, DN newSuperiorDN,
+  private void removeSubordinateEntry(Transaction txn, IndexBuffer buffer,
+      DN oldSuperiorDN,
       EntryID oldID, EntryID newID,
       Entry oldEntry, DN newDN,
       boolean isApexEntryMoved,
-      ModifyDNOperation modifyDNOperation)
+      ModifyDNOperation modifyDNOperation,
+      MovedEntry tail)
   throws DirectoryException, DatabaseException
   {
     DN oldDN = oldEntry.getDN();
@@ -2824,24 +2878,17 @@
     // Remove the old DN from dn2id.
     dn2id.remove(txn, oldDN);
 
-    // Put the new DN in dn2id.
-    if (!dn2id.insert(txn, newDN, newID))
-    {
-      Message message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get(newDN.toString());
-      throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS,
-          message);
-    }
-
     // Remove old ID from id2entry and put the new entry
     // (old entry with new DN) in id2entry.
     if (!newID.equals(oldID))
     {
       id2entry.remove(txn, oldID);
     }
-    id2entry.put(txn, newID, newEntry);
 
     // Update any referral records.
-    dn2uri.replaceEntry(txn, oldEntry, newEntry);
+    dn2uri.deleteEntry(txn, oldEntry);
+
+    tail.next = new MovedEntry(newID, newEntry, !newID.equals(oldID));
 
     if(isApexEntryMoved)
     {
@@ -2863,28 +2910,8 @@
       id2children.delete(buffer, oldIDKeyBytes);
       id2subtree.delete(buffer, oldIDKeyBytes);
 
-      // Add new ID to the id2c and id2s of our new parent and
-      // new ID to id2s up the tree.
-      EntryID newParentID;
-      byte[] parentIDKeyBytes;
-      boolean isParent = true;
-      for (DN superiorDN = newDN; superiorDN != null;
-      superiorDN = getParentWithinBase(superiorDN))
-      {
-        newParentID = dn2id.get(txn, superiorDN, LockMode.DEFAULT);
-        parentIDKeyBytes =
-          JebFormat.entryIDToDatabase(newParentID.longValue());
-        if(isParent)
-        {
-          id2children.insertID(buffer, parentIDKeyBytes, newID);
-          isParent = false;
-        }
-        id2subtree.insertID(buffer, parentIDKeyBytes, newID);
-      }
-
       // Reindex the entry with the new ID.
       indexRemoveEntry(buffer, oldEntry, oldID);
-      indexInsertEntry(buffer, newEntry, newID);
     }
     else
     {
@@ -2893,18 +2920,6 @@
       {
         indexModifications(buffer, oldEntry, newEntry, oldID, modifications);
       }
-
-      if(isApexEntryMoved)
-      {
-        // Add the new ID to the id2s of new apex superior entries.
-        for(DN dn = newSuperiorDN; dn != null; dn = getParentWithinBase(dn))
-        {
-          EntryID parentID = dn2id.get(txn, dn, LockMode.DEFAULT);
-          byte[] parentIDKeyBytes =
-            JebFormat.entryIDToDatabase(parentID.longValue());
-          id2subtree.insertID(buffer, parentIDKeyBytes, newID);
-        }
-      }
     }
 
     // Remove the entry from the entry cache.

--
Gitblit v1.10.0