From becf36cba38a762b3d9ee0b9d014c9db7330ebee Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Mon, 31 May 2010 09:49:21 +0000
Subject: [PATCH] Fix issue #3891 - Handle replication conflict when adding child entry and parent is deleted

---
 opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java |   63 +++++++++++++++++++++++++++++--
 1 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
index 4068db1..7e8c1cf 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/DeleteMsg.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.replication.protocol;
 
@@ -31,6 +31,7 @@
 import java.io.UnsupportedEncodingException;
 import java.util.zip.DataFormatException;
 
+import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.core.DeleteOperationBasis;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.replication.common.ChangeNumber;
@@ -43,7 +44,10 @@
  */
 public class DeleteMsg extends LDAPUpdateMsg
 {
-  String initiatorsName;
+  private String initiatorsName;
+
+  // whether the DEL operation is a subtree DEL
+  private boolean isSubtreeDelete = false;
 
   /**
    * Creates a new delete message.
@@ -54,15 +58,23 @@
   {
     super((OperationContext) operation.getAttachment(SYNCHROCONTEXT),
            operation.getRawEntryDN().toString());
+    try
+    {
+      if (operation.getRequestControl(SubtreeDeleteControl.DECODER) != null)
+        isSubtreeDelete = true;
+    }
+    catch(Exception e)
+    {}
+
   }
 
   /**
    * Creates a new delete message.
    *
-   * @param dn The dn with which the message must be created.
+   * @param dn           The dn with which the message must be created.
    * @param changeNumber The change number with which the message must be
    *                     created.
-   * @param uid The unique id with which the message must be created.
+   * @param uid          The unique id with which the message must be created.
    */
   public DeleteMsg(String dn, ChangeNumber changeNumber, String uid)
   {
@@ -87,6 +99,12 @@
     // protocol version has been read as part of the header
     if (protocolVersion >= 4)
       decodeBody_V4(in, pos);
+    else
+    {
+      // Keep the previous protocol version behavior - when we don't know the
+      // truth, we assume 'subtree'
+      isSubtreeDelete = true;
+    }
   }
 
 
@@ -101,6 +119,10 @@
         InternalClientConnection.nextOperationID(),
         InternalClientConnection.nextMessageID(), null,
         ByteString.valueOf(newDn));
+
+    if (isSubtreeDelete)
+      del.addRequestControl(new SubtreeDeleteControl(false));
+
     DeleteContext ctx = new DeleteContext(getChangeNumber(), getUniqueId());
     del.setAttachment(SYNCHROCONTEXT, ctx);
     return del;
@@ -152,6 +174,8 @@
     {
       bodyLength++;
     }
+    // subtree flag
+    bodyLength++;
 
     /* encode the header in a byte[] large enough to also contain the mods */
     byte [] encodedMsg = encodeHeader(MSG_TYPE_DELETE, bodyLength,
@@ -163,6 +187,9 @@
       encodedMsg[pos++] = 0;
     pos = addByteArray(byteEntryAttrLen, encodedMsg, pos);
     pos = addByteArray(encodedEclIncludes, encodedMsg, pos);
+
+    encodedMsg[pos++] = (isSubtreeDelete ? (byte) 1 : (byte) 0);
+
     return encodedMsg;
   }
 
@@ -173,7 +200,6 @@
   private void decodeBody_V4(byte[] in, int pos)
   throws DataFormatException, UnsupportedEncodingException
   {
-    // Read ecl attr len
     int length = getNextLength(in, pos);
     if (length != 0)
     {
@@ -185,15 +211,21 @@
       initiatorsName = null;
       pos += 1;
     }
+
+    // Read ecl attr len
     length = getNextLength(in, pos);
     int eclAttrLen = Integer.valueOf(new String(in, pos, length,"UTF-8"));
+    // Skip the length
     pos += length + 1;
 
     // Read/Don't decode entry attributes
     encodedEclIncludes = new byte[eclAttrLen];
     try
     {
+      // Copy ecl attr
       System.arraycopy(in, pos, encodedEclIncludes, 0, eclAttrLen);
+      // Skip the attrs
+      pos += eclAttrLen +1;
     } catch (IndexOutOfBoundsException e)
     {
       throw new DataFormatException(e.getMessage());
@@ -204,6 +236,10 @@
     {
       throw new DataFormatException(e.getMessage());
     }
+
+    // subtree flag
+    isSubtreeDelete = (in[pos] == 1);
+
   }
 
   /**
@@ -263,4 +299,21 @@
     return initiatorsName;
   }
 
+  /**
+   * Set the subtree flag.
+   * @param subtreeDelete the subtree flag.
+   */
+  public void setSubtreeDelete(boolean subtreeDelete)
+  {
+    this.isSubtreeDelete = subtreeDelete;
+  }
+
+  /**
+   * Get the subtree flag.
+   * @return the subtree flag.
+   */
+  public boolean isSubtreeDelete()
+  {
+    return this.isSubtreeDelete;
+  }
 }

--
Gitblit v1.10.0