From 9d7725370d82557e35ed802a6a7bc206c44b993b Mon Sep 17 00:00:00 2001
From: sin <sin@localhost>
Date: Tue, 10 Jul 2007 16:50:42 +0000
Subject: [PATCH] Bug# 1462:server deadlock on subtree delete Fix: Introduce a batch parameter to create the additional transactions for a new batch.

---
 opends/src/server/org/opends/server/backends/jeb/EntryContainer.java |   94 ++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 76 insertions(+), 18 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 d01b39e..47a80a4 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -182,6 +182,8 @@
 
   private int subtreeDeleteSizeLimit;
 
+  private int subtreeDeleteBatchSize;
+
   private int indexEntryLimit;
 
   /**
@@ -215,6 +217,7 @@
     this.rootContainer = rootContainer;
     this.deadlockRetryLimit = config.getBackendDeadlockRetryLimit();
     this.subtreeDeleteSizeLimit = config.getBackendSubtreeDeleteSizeLimit();
+    this.subtreeDeleteBatchSize = config.getBackendSubtreeDeleteBatchSize();
     this.indexEntryLimit = config.getBackendIndexEntryLimit();
 
     // Instantiate the attribute indexes.
@@ -1678,24 +1681,33 @@
   {
     DeleteEntryTransaction operation =
         new DeleteEntryTransaction(entryDN, deleteOperation);
-
-    invokeTransactedOperation(operation);
-
-    if (operation.adminSizeLimitExceeded())
+    boolean isComplete = false;
+    while(!isComplete)
     {
-      String message = getMessage(MSGID_JEB_SUBTREE_DELETE_SIZE_LIMIT_EXCEEDED,
+      invokeTransactedOperation(operation);
+
+      if (operation.adminSizeLimitExceeded())
+      {
+        String message = getMessage(
+                MSGID_JEB_SUBTREE_DELETE_SIZE_LIMIT_EXCEEDED,
                                   operation.getDeletedEntryCount());
-      throw new DirectoryException(
+        throw new DirectoryException(
           ResultCode.ADMIN_LIMIT_EXCEEDED,
           message,
           MSGID_JEB_SUBTREE_DELETE_SIZE_LIMIT_EXCEEDED);
-    }
-
-    String message = getMessage(MSGID_JEB_DELETED_ENTRY_COUNT,
+      }
+      if(operation.batchSizeExceeded())
+      {
+        operation.resetBatchSize();
+        continue;
+      }
+      isComplete = true;
+      String message = getMessage(MSGID_JEB_DELETED_ENTRY_COUNT,
                                 operation.getDeletedEntryCount());
-    StringBuilder errorMessage = new StringBuilder();
-    errorMessage.append(message);
-    deleteOperation.setErrorMessage(errorMessage);
+      StringBuilder errorMessage = new StringBuilder();
+      errorMessage.append(message);
+      deleteOperation.setErrorMessage(errorMessage);
+    }
   }
 
   /**
@@ -1930,7 +1942,7 @@
     private DeleteOperation deleteOperation;
 
     /**
-     * A list of the DNs of all entries deleted by this operation.
+     * A list of the DNs of all entries deleted by this operation in a batch.
      * The subtree delete control can cause multiple entries to be deleted.
      */
     private ArrayList<DN> deletedDNList;
@@ -1941,6 +1953,18 @@
      */
     private boolean adminSizeLimitExceeded = false;
 
+
+    /**
+     * Indicates whether the subtree delete batch size has been exceeded.
+     */
+    private boolean batchSizeExceeded = false;
+
+
+    /**
+     * Indicates the count of deleted DNs in the Delete Operation.
+     */
+    private int countDeletedDN;
+
     /**
      * Create a new Delete Entry Transaction.
      * @param entryDN The entry or subtree to be deleted.
@@ -1963,12 +1987,31 @@
     }
 
     /**
+     * Determine whether the subtree delete batch size has been exceeded.
+     * @return true if the batch size has been exceeded.
+     */
+    public boolean batchSizeExceeded()
+    {
+      return batchSizeExceeded;
+    }
+
+    /**
+     * Resets the batchSizeExceeded parameter to reuse the object
+     * for multiple batches.
+     */
+    public void resetBatchSize()
+    {
+      batchSizeExceeded=false;
+      deletedDNList.clear();
+    }
+
+    /**
      * Get the number of entries deleted during the operation.
      * @return The number of entries deleted.
      */
     public int getDeletedEntryCount()
     {
-      return deletedDNList.size();
+      return countDeletedDN;
     }
 
     /**
@@ -1999,6 +2042,7 @@
 
       // Determine whether this is a subtree delete.
       int adminSizeLimit = subtreeDeleteSizeLimit;
+      int deleteBatchSize = subtreeDeleteBatchSize;
       boolean isSubtreeDelete = false;
       List<Control> controls = deleteOperation.getRequestControls();
       if (controls != null)
@@ -2082,12 +2126,19 @@
           }
 
           // Enforce any subtree delete size limit.
-          if (adminSizeLimit > 0 && deletedDNList.size() >= adminSizeLimit)
+          if (adminSizeLimit > 0 && countDeletedDN >= adminSizeLimit)
           {
             adminSizeLimitExceeded = true;
             break;
           }
 
+          // Enforce any subtree delete batch size.
+          if (deleteBatchSize > 0 && deletedDNList.size() >= deleteBatchSize)
+          {
+            batchSizeExceeded = true;
+            break;
+          }
+
           /*
            * Delete this entry which by now must be a leaf because
            * we have been deleting from the bottom of the tree upwards.
@@ -2098,7 +2149,7 @@
                      txn, subordinateDN, entryID);
 
           deletedDNList.add(subordinateDN);
-
+          countDeletedDN++;
           status = cursor.getPrev(key, data, LockMode.DEFAULT);
         }
       }
@@ -2109,13 +2160,18 @@
 
       // Finally delete the target entry as it was not included
       // in the dn2id iteration.
-      if (!adminSizeLimitExceeded)
+      if (!adminSizeLimitExceeded && !batchSizeExceeded)
       {
         // Enforce any subtree delete size limit.
-        if (adminSizeLimit > 0 && deletedDNList.size() >= adminSizeLimit)
+        if (adminSizeLimit > 0 && countDeletedDN >= adminSizeLimit)
         {
           adminSizeLimitExceeded = true;
         }
+        else if (deleteBatchSize > 0 &&
+                                      deletedDNList.size() >= deleteBatchSize)
+        {
+          batchSizeExceeded = true;
+        }
         else
         {
           boolean manageDsaIT;
@@ -2134,6 +2190,7 @@
           deleteTarget(manageDsaIT, id2cBuffered, id2sBuffered, txn, entryDN);
 
           deletedDNList.add(entryDN);
+          countDeletedDN++;
         }
       }
 
@@ -3762,6 +3819,7 @@
     this.config = cfg;
     this.deadlockRetryLimit = config.getBackendDeadlockRetryLimit();
     this.subtreeDeleteSizeLimit = config.getBackendSubtreeDeleteSizeLimit();
+    this.subtreeDeleteBatchSize = config.getBackendSubtreeDeleteBatchSize();
     this.indexEntryLimit = config.getBackendIndexEntryLimit();
     return new ConfigChangeResult(ResultCode.SUCCESS,
                                   adminActionRequired, messages);

--
Gitblit v1.10.0