From f09c069e92d051036af2a969fe5289cb7c4826ba Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 26 Oct 2015 08:22:49 +0000
Subject: [PATCH] OPENDJ-2349: fix deadlocks during subtree deletes and moddn

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
index 903b98f..1d0704d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
@@ -29,7 +29,9 @@
 import static org.opends.server.backends.pluggable.CursorTransformer.*;
 import static org.opends.server.backends.pluggable.DnKeyFormat.*;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.NoSuchElementException;
 
 import org.forgerock.opendj.ldap.ByteSequence;
@@ -37,6 +39,7 @@
 import org.forgerock.opendj.ldap.ByteStringBuilder;
 import org.forgerock.opendj.ldap.Functions;
 import org.forgerock.util.Function;
+import org.forgerock.util.Pair;
 import org.forgerock.util.promise.NeverThrowsException;
 import org.opends.server.backends.pluggable.OnDiskMergeImporter.SequentialCursorDecorator;
 import org.opends.server.backends.pluggable.spi.Cursor;
@@ -46,7 +49,9 @@
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.UpdateFunction;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;
+import org.opends.server.types.CanceledOperationException;
 import org.opends.server.types.DN;
+import org.opends.server.types.Operation;
 
 /**
  * This class represents the dn2id index, which has one record
@@ -178,6 +183,44 @@
     return transformKeysAndValues(new SubtreeCursor(openCursor0(txn, dn)), TO_VOID_KEY, TO_ENTRY_ID);
   }
 
+  List<Pair<Long, Long>> renameSubtree(WriteableTransaction txn,
+                                       DN oldName,
+                                       DN newName,
+                                       RootContainer rootContainer,
+                                       boolean renumberEntryIDs,
+                                       Operation operation)
+          throws CanceledOperationException
+  {
+    try (SequentialCursor<ByteString, ByteString> cursor = new SubtreeCursor(openCursor0(txn, oldName)))
+    {
+      List<Pair<Long, Long>> renamedEntryIDs = new ArrayList<>();
+      int oldTargetDnKeyLength = toKey(oldName).length();
+      ByteString newTargetDnKey = toKey(newName);
+
+      do
+      {
+        ByteString currentDnKey = cursor.getKey();
+        EntryID oldID = new EntryID(cursor.getValue());
+        cursor.delete();
+
+        ByteString newDnKeySuffix = currentDnKey.subSequence(oldTargetDnKeyLength, currentDnKey.length());
+        ByteSequence newDnKey = new ByteStringBuilder(newTargetDnKey).append(newDnKeySuffix);
+        EntryID newID = renumberEntryIDs ? rootContainer.getNextEntryID() : oldID;
+        txn.put(getName(), newDnKey, newID.toByteString());
+
+        renamedEntryIDs.add(Pair.of(oldID.longValue(), newID.longValue()));
+
+        if (operation != null)
+        {
+          operation.checkIfCanceled(false);
+        }
+      }
+      while (cursor.next());
+
+      return renamedEntryIDs;
+    }
+  }
+
   /**
    * Check if two DN have a parent-child relationship.
    *
@@ -389,6 +432,12 @@
     }
 
     @Override
+    public void delete() throws NoSuchElementException, UnsupportedOperationException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void close()
     {
       delegate.close();

--
Gitblit v1.10.0