andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 6 months ago
Clone

Blame 0209-Ticket-47750-Creating-a-glue-fails-if-one-above-leve.patch

dc8c34
From 7299b3561fa579b6b90bbf3becc821b91429c9ac Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Fri, 9 May 2014 09:53:36 -0700
dc8c34
Subject: [PATCH 209/225] Ticket #47750 - Creating a glue fails if one above
dc8c34
 level is a conflict or missing
dc8c34
dc8c34
Including the fix for Ticket #47696 - Large Searches Hang - Possibly entryrdn related
dc8c34
dc8c34
Bug Descriptions:
dc8c34
There were multiple issues to break the parent-child relationship when a
dc8c34
resurrect occurred.
dc8c34
When resurrecting a tombstone, there is a possibility that an entry having
dc8c34
the same name was already added.  In the case, the code consdered the entry
dc8c34
is already there, which confused the numsubordinates and tombstone-num-
dc8c34
subordinates count.  If it is detected, it creates a conflict glue entry
dc8c34
instead of a pure glue entry.  The 2 numsubordinates counts were also not
dc8c34
correctly updated in the resurrection case. When the entryrdn was introduced,
dc8c34
Slapi_RDN was held in the entry, which was not correctly updated in the
dc8c34
resurrect case.
dc8c34
dc8c34
Fix Descriptions:
dc8c34
[replication/urp.c]
dc8c34
urp_fixup_rename_entry sets the parent uniqueid if it is a RESURRECT mode
dc8c34
(called from tombstone_to_glue) as being done in urp_fixup_add_entry, which
dc8c34
is necessary to retrieve the correct parent in ldbm_back_modrdn.
dc8c34
dc8c34
[replication/urp_glue.c]
dc8c34
In create_glue_entry,
dc8c34
. there was a possibility to pass a tombstone DN (nsuniqueid=...,<DN>) is
dc8c34
  used to create a glue entry.  If found, the part is removed before passing
dc8c34
  it to create a glue entry.
dc8c34
. there is a possibility to create a glue entry fails due to the parent entry
dc8c34
  not found.  This occurs when the parent entry has turned to be a conflict
dc8c34
  entry.  In the case, instead of retrying the glue creation, it logs an
dc8c34
  error and returns.
dc8c34
dc8c34
[replication/urp_tombstone.c]
dc8c34
In tombstone_to_glue,
dc8c34
. turning a tombstone to an ordinary glue entry could fail with the entry
dc8c34
  already exists.  (Note: ldbm_back_add guarantees that the found entry has
dc8c34
  a different nsuniqueid from this tombstone has.)  This situation occurs an
dc8c34
  entry having the same dn could have been added/replicated by this moment.
dc8c34
  And the entry cannot be used for this tombstone to resurrect since the
dc8c34
  subordinates/tombstonesubordinates relationships get corrupted. To maintain
dc8c34
  the relationship properly, the tombstone is resurrected as a conflict, glue
dc8c34
  entry using urp_fixup_rename_entry.  If it still returns LDAP_ALREADY_EXISTS,
dc8c34
  it is assured the expected glue entry exists since the same nsuniqueid is
dc8c34
  shared.
dc8c34
dc8c34
[slapd/back-ldbm/ldbm_add.c]
dc8c34
In ldbm_back_add,
dc8c34
. in is_resurect_operation case, a SLAPI_ADD_EXISTING_DN_ENTRY entry and a
dc8c34
  SLAPI_ADD_EXISTING_UNIQUEID_ENTRY entry are identical, it returns SUCCESS
dc8c34
  instead of LDAP_ALREADY_EXISTS.
dc8c34
. in is_resurect_operation case, the DN is modified from the tombstone DN
dc8c34
  to the ordinary DN.  The DN is stored in e_sdn as well as in e_srdn in the
dc8c34
  Slapi_Entry.  The e_srdn part was not updated.  This patch fixes it and
dc8c34
  e_sdn and e_srdn are in sync.
dc8c34
. parent_update_on_childchange adjusts the count of numsubordinates and
dc8c34
  tombstonenumsubordinates.  It only took PARENTUPDATE_ADD|_DELETE operations.
dc8c34
  This patch adds PARENTUPDATE_RESURECT operation to increment numsubordinates
dc8c34
  and decrement tombstonenumsubordinates at the same time.
dc8c34
. in is_resurect_operation case, a tombstone to be replaced with a glue entry
dc8c34
  needs to be deleted from the entryrdn index, which was missing.
dc8c34
dc8c34
[slapd/back-ldbm/ldbm_delete.c]
dc8c34
. Check the target DN if it starts with "nsuniqueid=...,", if it is, log an
dc8c34
  error and returns.
dc8c34
dc8c34
[slapd/back-ldbm/ldbm_modrdn.c]
dc8c34
. If it is is_resurect_operation case, it allows to rename a tombstone entry.
dc8c34
  This is used to support to change a tombstone entry to a conflict glue entry
dc8c34
  in tombstone_to_glue.
dc8c34
. ldbm_back_modify checks if the renamed entry has children or not and if
dc8c34
  there are, they are updated to point to the renamed entry.  The check
dc8c34
  function slapi_entry_has_children was just checking the numsubordinates
dc8c34
  attribute type.  If a positive value is returned, it took care all the
dc8c34
  children including the tombstones, but if the renamed entry had tombstoned
dc8c34
  children only, it considered there were no children and the tombstoned
dc8c34
  children were not updated to point the renamed entry.  This patch fixes it.
dc8c34
dc8c34
[slapd/back-ldbm/ldbm_entryrdn.c]
dc8c34
. Added a flag to entryrdn_rename_subtree and entryrdn_get_subordinates to
dc8c34
  treat the given DN a tombstoned DN if it is.
dc8c34
dc8c34
In addition, helper APIs such as slapi_rdn_is_multivalued and slapi_rdn_is_
dc8c34
conflict, and slapi_is_special_rdn are added.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47750
dc8c34
dc8c34
Reviewed by mreynolds@redhat.com (Thank you, Mark!!)
dc8c34
(cherry picked from commit 9e5b3332cc33167837fce0477c8a4d0edc42f0db)
dc8c34
---
dc8c34
 ldap/servers/plugins/replication/repl5.h         |   1 +
dc8c34
 ldap/servers/plugins/replication/urp.c           |  79 +++--
dc8c34
 ldap/servers/plugins/replication/urp.h           |   5 +-
dc8c34
 ldap/servers/plugins/replication/urp_glue.c      |  32 +-
dc8c34
 ldap/servers/plugins/replication/urp_tombstone.c |  55 +++-
dc8c34
 ldap/servers/slapd/add.c                         |  15 +-
dc8c34
 ldap/servers/slapd/back-ldbm/back-ldbm.h         |   3 +-
dc8c34
 ldap/servers/slapd/back-ldbm/backentry.c         |   1 +
dc8c34
 ldap/servers/slapd/back-ldbm/cache.c             | 103 ++++---
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_add.c          | 362 ++++++++++++++---------
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_delete.c       | 337 ++++++++++++++-------
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c     |  12 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modify.c       |  41 ++-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modrdn.c       | 281 ++++++++++++++----
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_search.c       |   2 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldif2ldbm.c         |   2 +-
dc8c34
 ldap/servers/slapd/back-ldbm/parents.c           |  31 +-
dc8c34
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h   |   5 +-
dc8c34
 ldap/servers/slapd/entry.c                       |  38 ++-
dc8c34
 ldap/servers/slapd/rdn.c                         | 108 ++++++-
dc8c34
 ldap/servers/slapd/slapi-plugin.h                |  45 +++
dc8c34
 ldap/servers/slapd/slapi-private.h               |   7 +
dc8c34
 ldap/servers/slapd/util.c                        |  67 +++++
dc8c34
 23 files changed, 1184 insertions(+), 448 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
dc8c34
index b10b358..a5761be 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5.h
dc8c34
+++ b/ldap/servers/plugins/replication/repl5.h
dc8c34
@@ -60,6 +60,7 @@
dc8c34
 #include "llist.h"
dc8c34
 #include "repl5_ruv.h"
dc8c34
 #include "cl4.h"
dc8c34
+#include "plstr.h"
dc8c34
 
dc8c34
 #define REPLICA_TYPE_WINDOWS 1
dc8c34
 #define REPLICA_TYPE_MULTIMASTER 0
dc8c34
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
dc8c34
index 9787ff7..0182af3 100644
dc8c34
--- a/ldap/servers/plugins/replication/urp.c
dc8c34
+++ b/ldap/servers/plugins/replication/urp.c
dc8c34
@@ -58,7 +58,6 @@ static int urp_naming_conflict_removal (Slapi_PBlock *pb, char *sessionid, CSN *
dc8c34
 static int mod_namingconflict_attr (const char *uniqueid, const Slapi_DN *entrysdn, const Slapi_DN *conflictsdn, CSN *opcsn);
dc8c34
 static int del_replconflict_attr (Slapi_Entry *entry, CSN *opcsn, int opflags);
dc8c34
 static char *get_dn_plus_uniqueid(char *sessionid,const Slapi_DN *oldsdn,const char *uniqueid);
dc8c34
-static char *get_rdn_plus_uniqueid(char *sessionid,const char *olddn,const char *uniqueid);
dc8c34
 static int is_suffix_entry (Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parenddn);
dc8c34
 
dc8c34
 /*
dc8c34
@@ -372,6 +371,9 @@ urp_modrdn_operation( Slapi_PBlock *pb )
dc8c34
 			slapi_entry_get_sdn (target_entry), "renameTombstone", opcsn);
dc8c34
 		*/
dc8c34
 		op_result = LDAP_NO_SUCH_OBJECT;
dc8c34
+		slapi_log_error(SLAPI_LOG_REPL, sessionid,
dc8c34
+		                "urp_modrdn: target_entry %s is a tombstone; returning NO_SUCH_OBJECT.\n",
dc8c34
+		                slapi_entry_get_dn(target_entry));
dc8c34
 		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
dc8c34
 		if (op_result == 0)
dc8c34
 		{
dc8c34
@@ -448,16 +450,16 @@ urp_modrdn_operation( Slapi_PBlock *pb )
dc8c34
 				slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
dc8c34
 				rc= -1; /* Ignore this Operation */
dc8c34
 				PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists;
dc8c34
-								  Unique ID already in RDN - Change to Lost and Found entry */
dc8c34
+				                  Unique ID already in RDN - Change to Lost and Found entry */
dc8c34
 				goto bailout;
dc8c34
 			}
dc8c34
 			mod_namingconflict_attr (op_uniqueid, target_sdn, existing_sdn, opcsn);
dc8c34
 			slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, newrdn_with_uniqueid); 
dc8c34
 			slapi_log_error(slapi_log_urp, sessionid,
dc8c34
-					"Naming conflict MODRDN. Rename target entry to %s\n",
dc8c34
-					newrdn_with_uniqueid );
dc8c34
+			                "urp_modrdn_operation: Naming conflict MODRDN. Rename target entry from %s to %s\n",
dc8c34
+			                newrdn, newrdn_with_uniqueid );
dc8c34
 
dc8c34
-			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
dc8c34
+			rc= slapi_setbit_int(rc, SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
dc8c34
 			PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Operation Entry */
dc8c34
 			goto bailout;
dc8c34
 		}
dc8c34
@@ -608,14 +610,20 @@ urp_delete_operation( Slapi_PBlock *pb )
dc8c34
 		op_result= LDAP_NO_SUCH_OBJECT;
dc8c34
 		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
dc8c34
 		rc= -1; /* Don't apply the Delete */
dc8c34
+		slapi_log_error(slapi_log_urp, "no sessionid",
dc8c34
+		                "Entry %s does not exist; returning NO_SUCH_OBJECT.\n",
dc8c34
+		                slapi_entry_get_dn(deleteentry));
dc8c34
 		PROFILE_POINT; /* Delete Operation; Entry not exist. */
dc8c34
 	}
dc8c34
 	else if(is_tombstone_entry(deleteentry))
dc8c34
 	{
dc8c34
 		/* The entry is already a Tombstone, ignore this delete. */
dc8c34
-		op_result= LDAP_SUCCESS;
dc8c34
+		op_result= LDAP_ALREADY_EXISTS;
dc8c34
 		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
dc8c34
 		rc = -1; /* Don't apply the Delete */
dc8c34
+		slapi_log_error(slapi_log_urp, "no sessionid",
dc8c34
+		                "Entry %s is already a tombstone; returning ALREADY_EXISTS.\n",
dc8c34
+		                slapi_entry_get_dn(deleteentry));
dc8c34
 		PROFILE_POINT; /* Delete Operation; Already a Tombstone. */
dc8c34
 	}
dc8c34
 	else /* The entry to be deleted exists and is not a tombstone */
dc8c34
@@ -639,7 +647,10 @@ urp_delete_operation( Slapi_PBlock *pb )
dc8c34
 			op_result= LDAP_SUCCESS;
dc8c34
 			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
dc8c34
 			rc = -1; /* Don't apply the Delete */
dc8c34
-		    PROFILE_POINT; /* Delete Operation; Entry has children. */
dc8c34
+			slapi_log_error(slapi_log_urp, sessionid,
dc8c34
+			                "Entry %s was turned to a glue; returning SUCCESS.\n",
dc8c34
+			                slapi_entry_get_dn(deleteentry) );
dc8c34
+			PROFILE_POINT; /* Delete Operation; Entry has children. */
dc8c34
 		}
dc8c34
 	}
dc8c34
 	return rc;
dc8c34
@@ -785,7 +796,7 @@ urp_fixup_add_entry (Slapi_Entry *e, const char *target_uniqueid, const char *pa
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
-urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, int opflags)
dc8c34
+urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, const char *parentuniqueid, int opflags)
dc8c34
 {
dc8c34
 	Slapi_PBlock *newpb;
dc8c34
     Slapi_Operation *op;
dc8c34
@@ -813,7 +824,12 @@ urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, int opflags)
dc8c34
 	opcsn = (CSN *)entry_get_dncsn (entry);
dc8c34
     slapi_pblock_get (newpb, SLAPI_OPERATION, &op);
dc8c34
     operation_set_csn (op, opcsn);
dc8c34
-
dc8c34
+	if (parentuniqueid)
dc8c34
+	{
dc8c34
+		struct slapi_operation_parameters *op_params;
dc8c34
+		slapi_pblock_get( newpb, SLAPI_OPERATION_PARAMETERS, &op_params );
dc8c34
+		op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid = (char*)parentuniqueid; /* Consumes parentuniqueid */
dc8c34
+	}
dc8c34
 	slapi_modrdn_internal_pb(newpb); 
dc8c34
     slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
dc8c34
 
dc8c34
@@ -1012,7 +1028,7 @@ urp_annotate_dn (char *sessionid, Slapi_Entry *entry, CSN *opcsn, const char *op
dc8c34
 	if(newrdn!=NULL)
dc8c34
 	{
dc8c34
 		mod_namingconflict_attr (uniqueid, basesdn, basesdn, opcsn);
dc8c34
-		op_result = urp_fixup_rename_entry ( entry, newrdn, 0 );
dc8c34
+		op_result = urp_fixup_rename_entry ( entry, newrdn, NULL, 0 );
dc8c34
 		switch(op_result)
dc8c34
 		{
dc8c34
 		case LDAP_SUCCESS:
dc8c34
@@ -1191,7 +1207,7 @@ urp_naming_conflict_removal ( Slapi_PBlock *pb, char *sessionid, CSN *opcsn, con
dc8c34
 	 * is done after DB lock was released. The backend modrdn
dc8c34
 	 * will acquire the DB lock if it sees this flag.
dc8c34
 	 */
dc8c34
-	op_result = urp_fixup_rename_entry (min_naming_conflict_entry, newrdnstr, OP_FLAG_ACTION_INVOKE_FOR_REPLOP);
dc8c34
+	op_result = urp_fixup_rename_entry (min_naming_conflict_entry, newrdnstr, NULL, OP_FLAG_ACTION_INVOKE_FOR_REPLOP);
dc8c34
 	if ( op_result != LDAP_SUCCESS )
dc8c34
 	{
dc8c34
 	    slapi_log_error (slapi_log_urp, sessionid,
dc8c34
@@ -1224,15 +1240,19 @@ bailout:
dc8c34
 static char *
dc8c34
 get_dn_plus_uniqueid(char *sessionid, const Slapi_DN *oldsdn, const char *uniqueid)
dc8c34
 {
dc8c34
-	Slapi_RDN *rdn= slapi_rdn_new();
dc8c34
-	char *newdn;
dc8c34
+	Slapi_RDN *rdn = slapi_rdn_new();
dc8c34
+	char *newdn = NULL;
dc8c34
+	int rc = slapi_rdn_init_all_sdn_ext(rdn, oldsdn, 1);
dc8c34
+	if (rc) {
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, sessionid,
dc8c34
+		                "Failed to convert %s to RDN\n", slapi_sdn_get_dn(oldsdn));
dc8c34
+		goto bail;
dc8c34
+	}
dc8c34
 
dc8c34
 	PR_ASSERT(uniqueid!=NULL);
dc8c34
 
dc8c34
 	/* Check if the RDN already contains the Unique ID */
dc8c34
-	slapi_rdn_set_dn(rdn, slapi_sdn_get_dn(oldsdn));
dc8c34
-	if(slapi_rdn_contains(rdn,SLAPI_ATTR_UNIQUEID,uniqueid,strlen(uniqueid)))
dc8c34
-	{
dc8c34
+	if (slapi_rdn_is_conflict(rdn)) {
dc8c34
 		/* The Unique ID is already in the RDN.
dc8c34
 		 * This is a highly improbable collision.
dc8c34
 		 * It suggests that a duplicate UUID was generated.
dc8c34
@@ -1241,7 +1261,6 @@ get_dn_plus_uniqueid(char *sessionid, const Slapi_DN *oldsdn, const char *unique
dc8c34
 		 */
dc8c34
 		slapi_log_error(SLAPI_LOG_FATAL, sessionid,
dc8c34
 				"Annotated DN %s has naming conflict\n", slapi_sdn_get_dn(oldsdn) );
dc8c34
-		newdn= NULL;
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{
dc8c34
@@ -1250,21 +1269,27 @@ get_dn_plus_uniqueid(char *sessionid, const Slapi_DN *oldsdn, const char *unique
dc8c34
 		newdn = slapi_ch_smprintf("%s,%s", slapi_rdn_get_rdn(rdn), parentdn);
dc8c34
 		slapi_ch_free_string(&parentdn);
dc8c34
 	}
dc8c34
+bail:
dc8c34
 	slapi_rdn_free(&rdn;;
dc8c34
 	return newdn;
dc8c34
 }
dc8c34
 
dc8c34
-static char *
dc8c34
+char *
dc8c34
 get_rdn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid)
dc8c34
 {
dc8c34
-	char *newrdn;
dc8c34
+	char *newrdn = NULL;
dc8c34
 	/* Check if the RDN already contains the Unique ID */
dc8c34
-	Slapi_DN *sdn= slapi_sdn_new_dn_byval(olddn);
dc8c34
-	Slapi_RDN *rdn= slapi_rdn_new();
dc8c34
-	slapi_sdn_get_rdn(sdn,rdn);
dc8c34
+	Slapi_DN *sdn = slapi_sdn_new_dn_byval(olddn);
dc8c34
+	Slapi_RDN *rdn = slapi_rdn_new();
dc8c34
+	int rc = slapi_rdn_init_all_sdn_ext(rdn, sdn, 1);
dc8c34
+	if (rc) {
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, sessionid,
dc8c34
+		                "Failed to convert %s to RDN\n", olddn);
dc8c34
+		goto bail;
dc8c34
+	}
dc8c34
+
dc8c34
 	PR_ASSERT(uniqueid!=NULL);
dc8c34
-	if(slapi_rdn_contains(rdn,SLAPI_ATTR_UNIQUEID,uniqueid,strlen(uniqueid)))
dc8c34
-	{
dc8c34
+	if (slapi_rdn_is_conflict(rdn)) {
dc8c34
 		/* The Unique ID is already in the RDN.
dc8c34
 		 * This is a highly improbable collision.
dc8c34
 		 * It suggests that a duplicate UUID was generated.
dc8c34
@@ -1272,14 +1297,14 @@ get_rdn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid)
dc8c34
 		 * require admin intercession
dc8c34
 		 */
dc8c34
 		slapi_log_error(SLAPI_LOG_FATAL, sessionid,
dc8c34
-				"Annotated DN %s has naming conflict\n", olddn );
dc8c34
-		newrdn= NULL;
dc8c34
+		                "Annotated RDN %s has naming conflict\n", olddn);
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{
dc8c34
 		slapi_rdn_add(rdn,SLAPI_ATTR_UNIQUEID,uniqueid);
dc8c34
-		newrdn= slapi_ch_strdup(slapi_rdn_get_rdn(rdn));
dc8c34
+		newrdn = slapi_ch_strdup(slapi_rdn_get_rdn(rdn));
dc8c34
 	}
dc8c34
+bail:
dc8c34
 	slapi_sdn_free(&sdn;;
dc8c34
 	slapi_rdn_free(&rdn;;
dc8c34
 	return newrdn;
dc8c34
diff --git a/ldap/servers/plugins/replication/urp.h b/ldap/servers/plugins/replication/urp.h
dc8c34
index ec7c94d..c7d8ca5 100644
dc8c34
--- a/ldap/servers/plugins/replication/urp.h
dc8c34
+++ b/ldap/servers/plugins/replication/urp.h
dc8c34
@@ -55,11 +55,12 @@ int urp_delete_operation( Slapi_PBlock *pb );
dc8c34
 int urp_post_delete_operation( Slapi_PBlock *pb );
dc8c34
 int urp_modrdn_operation( Slapi_PBlock *pb );
dc8c34
 int urp_post_modrdn_operation( Slapi_PBlock *pb );
dc8c34
+char *get_rdn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid);
dc8c34
 
dc8c34
 /* urp internal ops */
dc8c34
 int urp_fixup_add_entry (Slapi_Entry *e, const char *target_uniqueid, const char *parentuniqueid, CSN *opcsn, int opflags);
dc8c34
 int urp_fixup_delete_entry (const char *uniqueid, const char *dn, CSN *opcsn, int opflags);
dc8c34
-int urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, int opflags);
dc8c34
+int urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, const char *parentuniqueid, int opflags);
dc8c34
 int urp_fixup_modify_entry (const char *uniqueid, const Slapi_DN *sdn, CSN *opcsn, Slapi_Mods *smods, int opflags);
dc8c34
 
dc8c34
 int is_suffix_dn (Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn);
dc8c34
@@ -78,6 +79,6 @@ PRBool get_glue_csn(const Slapi_Entry *entry, const CSN **gluecsn);
dc8c34
  * urp_tombstone.c
dc8c34
  */
dc8c34
 int is_tombstone_entry(const Slapi_Entry* entry);
dc8c34
-int tombstone_to_glue(Slapi_PBlock *pb, const char *sessionid, Slapi_Entry *entry, const Slapi_DN *parentdn, const char *reason, CSN *opcsn);
dc8c34
+int tombstone_to_glue(Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, const Slapi_DN *parentdn, const char *reason, CSN *opcsn);
dc8c34
 int entry_to_tombstone ( Slapi_PBlock *pb, Slapi_Entry *entry );
dc8c34
 PRBool get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn);
dc8c34
diff --git a/ldap/servers/plugins/replication/urp_glue.c b/ldap/servers/plugins/replication/urp_glue.c
dc8c34
index 6eeb826..199d4de 100644
dc8c34
--- a/ldap/servers/plugins/replication/urp_glue.c
dc8c34
+++ b/ldap/servers/plugins/replication/urp_glue.c
dc8c34
@@ -153,7 +153,7 @@ static const char *glue_entry =
dc8c34
 	"objectclass: top\n"
dc8c34
 	"objectclass: extensibleObject\n" /* JCMREPL - To avoid schema checking. */
dc8c34
 	"objectclass: glue\n"
dc8c34
-	"nsuniqueid: %s\n"
dc8c34
+	"nsuniqueid: %s\n" /* this uniqueid is set to Slapi_Entry in slapi_str2entry. */
dc8c34
 	"%s: %s\n"; /* Add why it's been created */
dc8c34
 
dc8c34
 static int
dc8c34
@@ -166,15 +166,15 @@ do_create_glue_entry(const Slapi_RDN *rdn, const Slapi_DN *superiordn, const cha
dc8c34
 	Slapi_DN *sdn = NULL;
dc8c34
 	Slapi_RDN *newrdn = slapi_rdn_new_rdn(rdn);
dc8c34
 	char *estr, *rdnstr, *rdntype, *rdnval, *rdnpair;
dc8c34
-	sdn = slapi_sdn_new_dn_byval(slapi_sdn_get_ndn(superiordn));
dc8c34
+	sdn = slapi_sdn_new_ndn_byval(slapi_sdn_get_ndn(superiordn));
dc8c34
 	slapi_sdn_add_rdn(sdn,rdn);
dc8c34
 
dc8c34
 	/* must take care of multi-valued rdn: split rdn into different lines introducing
dc8c34
 	 * '\n' between each type/value pair. 
dc8c34
-	 */	
dc8c34
+	 */
dc8c34
 	alloc_len = RDNBUFSIZE;
dc8c34
 	rdnstr = slapi_ch_malloc(alloc_len);
dc8c34
-	rdnpair = rdnstr;	
dc8c34
+	rdnpair = rdnstr;
dc8c34
 	*rdnpair = '\0';   /* so that strlen(rdnstr) may return 0 the first time it's called */
dc8c34
 	while ((rdnval_index = slapi_rdn_get_next(newrdn, rdnval_index, &rdntype, &rdnval)) != -1) {
dc8c34
 	        rdntype_len = strlen(rdntype);
dc8c34
@@ -188,7 +188,7 @@ do_create_glue_entry(const Slapi_RDN *rdn, const Slapi_DN *superiordn, const cha
dc8c34
 		}
dc8c34
 		slapi_ldif_put_type_and_value_with_options(&rdnpair, rdntype, rdnval, rdnval_len, LDIF_OPT_NOWRAP);
dc8c34
 		*rdnpair = '\0';
dc8c34
-	}	  
dc8c34
+	}
dc8c34
 	estr= slapi_ch_smprintf(glue_entry, slapi_sdn_get_ndn(sdn), rdnstr, uniqueid, 
dc8c34
 			ATTR_NSDS5_REPLCONFLICT, reason);
dc8c34
 	slapi_ch_free((void**)&rdnstr);
dc8c34
@@ -196,9 +196,7 @@ do_create_glue_entry(const Slapi_RDN *rdn, const Slapi_DN *superiordn, const cha
dc8c34
 	slapi_ch_free((void**)&newrdn);
dc8c34
 	e = slapi_str2entry( estr, 0 );
dc8c34
 	PR_ASSERT(e!=NULL);
dc8c34
-	if ( e!=NULL )
dc8c34
-	{
dc8c34
-		slapi_entry_set_uniqueid (e, slapi_ch_strdup(uniqueid));
dc8c34
+	if (e) {
dc8c34
 		op_result = urp_fixup_add_entry (e, NULL, NULL, opcsn, 0);
dc8c34
 	}
dc8c34
 	slapi_ch_free_string(&estr);
dc8c34
@@ -232,7 +230,7 @@ create_glue_entry ( Slapi_PBlock *pb, char *sessionid, Slapi_DN *dn, const char
dc8c34
 
dc8c34
 		slapi_pblock_get( pb, SLAPI_BACKEND, &backend );
dc8c34
 		slapi_sdn_get_backend_parent ( dn, superiordn, backend );
dc8c34
-		slapi_sdn_get_rdn ( dn, rdn );
dc8c34
+		slapi_rdn_set_dn_ext(rdn, slapi_sdn_get_dn(dn), 1/* skip nsuniqeid=..., in dn */);
dc8c34
 
dc8c34
 		while(!done)
dc8c34
 		{
dc8c34
@@ -246,16 +244,30 @@ create_glue_entry ( Slapi_PBlock *pb, char *sessionid, Slapi_DN *dn, const char
dc8c34
 					done= 1;
dc8c34
 					break;
dc8c34
 				case LDAP_ALREADY_EXISTS:
dc8c34
+				{
dc8c34
+					struct slapi_operation_parameters *op_params;
dc8c34
+					/* This is okay.  While creating a glue, a real entry was added. */
dc8c34
 					slapi_log_error ( SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
 						"%s: Skipped creating glue entry %s uniqueid=%s reason Entry Already Exists\n",
dc8c34
 						sessionid, dnstr, uniqueid);
dc8c34
+					op_result = LDAP_SUCCESS;
dc8c34
+					/* If we could not create a glue having the nsuniqueid,
dc8c34
+					 * we have to abandon it. */
dc8c34
+					slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
dc8c34
+					slapi_ch_free_string(&op_params->p.p_add.parentuniqueid);
dc8c34
 					done= 1;
dc8c34
 					break;
dc8c34
+				}
dc8c34
 				case LDAP_NO_SUCH_OBJECT:
dc8c34
 					/* The parent is missing */
dc8c34
 					{
dc8c34
 					/* JCMREPL - Create the parent ... recursion?... but what's the uniqueid? */
dc8c34
-					PR_ASSERT(0); /* JCMREPL */
dc8c34
+					slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+						"%s: Can't created glue entry %s uniqueid=%s, error %d; "
dc8c34
+						"Possibly, parent entry is a conflict entry.\n",
dc8c34
+						sessionid, dnstr, uniqueid, op_result);
dc8c34
+					done= 1;
dc8c34
+					break;
dc8c34
 					}
dc8c34
 				default:
dc8c34
 					slapi_log_error ( SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
diff --git a/ldap/servers/plugins/replication/urp_tombstone.c b/ldap/servers/plugins/replication/urp_tombstone.c
dc8c34
index a61f1e5..68cb269 100644
dc8c34
--- a/ldap/servers/plugins/replication/urp_tombstone.c
dc8c34
+++ b/ldap/servers/plugins/replication/urp_tombstone.c
dc8c34
@@ -84,7 +84,7 @@ get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn)
dc8c34
 static int
dc8c34
 tombstone_to_glue_resolve_parent (
dc8c34
 	Slapi_PBlock *pb,
dc8c34
-	const char *sessionid,
dc8c34
+	char *sessionid,
dc8c34
 	const Slapi_DN *parentdn,
dc8c34
 	const char *parentuniqueid,
dc8c34
 	CSN *opcsn)
dc8c34
@@ -144,7 +144,7 @@ tombstone_to_glue_resolve_parent (
dc8c34
 int
dc8c34
 tombstone_to_glue (
dc8c34
 	Slapi_PBlock *pb,
dc8c34
-	const char *sessionid,
dc8c34
+	char *sessionid,
dc8c34
 	Slapi_Entry *tombstoneentry,
dc8c34
 	const Slapi_DN *tombstonedn,
dc8c34
 	const char *reason,
dc8c34
@@ -156,6 +156,7 @@ tombstone_to_glue (
dc8c34
 	Slapi_Entry *addingentry;
dc8c34
 	const char *addingdn;
dc8c34
 	int op_result;
dc8c34
+	int rdn_is_conflict = 0;
dc8c34
 
dc8c34
 	/* JCMREPL
dc8c34
 	 * Nothing logged to the 5.0 Change Log
dc8c34
@@ -170,18 +171,19 @@ tombstone_to_glue (
dc8c34
 	 * which won't help us identify the correct backend to search.
dc8c34
 	 */
dc8c34
 	is_suffix_dn_ext (pb, tombstonedn, &parentdn, 1 /* is_tombstone */);
dc8c34
-	parentuniqueid= slapi_entry_attr_get_charptr (tombstoneentry,
dc8c34
-			SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
dc8c34
+	parentuniqueid= slapi_entry_attr_get_charptr (tombstoneentry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
dc8c34
 	tombstone_to_glue_resolve_parent (pb, sessionid, parentdn, parentuniqueid, opcsn);
dc8c34
-	slapi_sdn_free(&parentdn);
dc8c34
 
dc8c34
-    /* Submit an Add operation to turn the tombstone entry into glue. */
dc8c34
+	/* Submit an Add operation to turn the tombstone entry into glue. */
dc8c34
 	/*
dc8c34
 	 * The tombstone is stored with an invalid DN, we must fix this.
dc8c34
 	 */
dc8c34
 	addingentry = slapi_entry_dup(tombstoneentry);
dc8c34
 	addingdn = slapi_sdn_get_dn(tombstonedn);
dc8c34
 	slapi_entry_set_sdn(addingentry, tombstonedn);
dc8c34
+	/* not just e_sdn, e_rsdn needs to be updated. */
dc8c34
+	slapi_rdn_set_all_dn(slapi_entry_get_srdn(addingentry), slapi_entry_get_dn_const(addingentry));
dc8c34
+	rdn_is_conflict = slapi_rdn_is_conflict(slapi_entry_get_srdn(addingentry));
dc8c34
 
dc8c34
 	if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason))
dc8c34
 	{
dc8c34
@@ -189,18 +191,57 @@ tombstone_to_glue (
dc8c34
 		slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason);
dc8c34
 	}
dc8c34
 	tombstoneuniqueid= slapi_entry_get_uniqueid(tombstoneentry);
dc8c34
-	op_result = urp_fixup_add_entry (addingentry, tombstoneuniqueid, parentuniqueid, opcsn, OP_FLAG_RESURECT_ENTRY);
dc8c34
+	/* 
dc8c34
+	 * addingentry and parentuniqueid are consumed in urp_fixup_add_entry,
dc8c34
+	 * regardless of the result.
dc8c34
+	 * Note: addingentry is not really consumed in ldbm_back_add.
dc8c34
+	 * tombstoneentry from DB/entry cache is duplicated and turned to be a glue.
dc8c34
+	 * This addingentry is freed in op_shared_add.
dc8c34
+	 */
dc8c34
+	op_result = urp_fixup_add_entry (addingentry, tombstoneuniqueid, slapi_ch_strdup(parentuniqueid), opcsn, OP_FLAG_RESURECT_ENTRY);
dc8c34
+	if ((LDAP_ALREADY_EXISTS == op_result) && !rdn_is_conflict) {
dc8c34
+		/* conflict -- there's already the same named entry added.
dc8c34
+		 * But this to-be-glued entry needs to be added since this is a parent of child entries...
dc8c34
+		 * So, rename this tombstone parententry a conflict, glue entry.
dc8c34
+		 * Instead of "fixup_add", we have to "fixup_rename"...
dc8c34
+		 * */
dc8c34
+		char *conflictrdn = get_rdn_plus_uniqueid(sessionid, addingdn, tombstoneuniqueid);
dc8c34
+		if (conflictrdn) {
dc8c34
+			addingentry = slapi_entry_dup(tombstoneentry);
dc8c34
+			if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason)) {
dc8c34
+				/* Add the reason of turning it to glue - The backend code will use it*/
dc8c34
+				slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason);
dc8c34
+			}
dc8c34
+			slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+			                 "%s: Can't resurrect tombstone to glue reason '%s'. "
dc8c34
+			                 "Try with conflict dn %s, error=%d\n",
dc8c34
+			                 sessionid, reason, addingdn, op_result);
dc8c34
+			op_result = urp_fixup_rename_entry(addingentry, (const char *)conflictrdn, parentuniqueid,
dc8c34
+			                                   OP_FLAG_RESURECT_ENTRY|OP_FLAG_TOMBSTONE_ENTRY);
dc8c34
+			slapi_entry_free(addingentry);
dc8c34
+			addingentry = NULL;
dc8c34
+		}
dc8c34
+	}
dc8c34
+	slapi_ch_free_string(&parentuniqueid);
dc8c34
 	if (op_result == LDAP_SUCCESS)
dc8c34
 	{
dc8c34
 		slapi_log_error (slapi_log_urp, repl_plugin_name,
dc8c34
 			"%s: Resurrected tombstone %s to glue reason '%s'\n", sessionid, addingdn, reason);
dc8c34
 	}
dc8c34
+	else if (LDAP_ALREADY_EXISTS == op_result)
dc8c34
+	{
dc8c34
+		slapi_log_error(slapi_log_urp, repl_plugin_name,
dc8c34
+		                "%s: No need to turn tombstone %s to glue; it was already resurrected.\n",
dc8c34
+		                sessionid, addingdn);
dc8c34
+		op_result = LDAP_SUCCESS;
dc8c34
+	}
dc8c34
 	else
dc8c34
 	{
dc8c34
 		slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
 			"%s: Can't resurrect tombstone %s to glue reason '%s', error=%d\n",
dc8c34
 			sessionid, addingdn, reason, op_result);
dc8c34
 	}
dc8c34
+	slapi_sdn_free(&parentdn);
dc8c34
 	return op_result;
dc8c34
 }
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
dc8c34
index 44a9aa2..1ce975a 100644
dc8c34
--- a/ldap/servers/slapd/add.c
dc8c34
+++ b/ldap/servers/slapd/add.c
dc8c34
@@ -699,10 +699,17 @@ static void op_shared_add (Slapi_PBlock *pb)
dc8c34
 
dc8c34
 				slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse;;
dc8c34
 				do_ps_service(pse, NULL, LDAP_CHANGETYPE_ADD, 0);
dc8c34
-
dc8c34
-				/* If be_add succeeded, then e is consumed.  We
dc8c34
-				 * set e to NULL to prevent freeing it ourselves. */
dc8c34
-				e = NULL;
dc8c34
+				/* 
dc8c34
+				 * If be_add succeeded, then e is consumed except the resurect case.
dc8c34
+				 * If it is resurect, the corresponding tombstone entry is resurected
dc8c34
+				 * and put into the cache.
dc8c34
+				 * Otherwise, we set e to NULL to prevent freeing it ourselves.
dc8c34
+				 */
dc8c34
+				if (operation_is_flag_set(operation,OP_FLAG_RESURECT_ENTRY) && save_e) {
dc8c34
+					e = save_e;
dc8c34
+				} else {
dc8c34
+					e = NULL;
dc8c34
+				}
dc8c34
 			}
dc8c34
 			else
dc8c34
 			{
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
dc8c34
index 8ad3c20..d27a664 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
dc8c34
@@ -893,7 +893,8 @@ typedef struct _back_search_result_set
dc8c34
 /* operation for parent_update_on_childchange */
dc8c34
 #define PARENTUPDATE_ADD       0x1
dc8c34
 #define PARENTUPDATE_DEL       0x2
dc8c34
-#define PARENTUPDATE_MASK      (PARENTUPDATE_ADD|PARENTUPDATE_DEL)
dc8c34
+#define PARENTUPDATE_RESURECT  0x4
dc8c34
+#define PARENTUPDATE_MASK      (PARENTUPDATE_ADD|PARENTUPDATE_DEL|PARENTUPDATE_RESURECT)
dc8c34
 
dc8c34
 #define PARENTUPDATE_CREATE_TOMBSTONE  0x10
dc8c34
 #define PARENTUPDATE_DELETE_TOMBSTONE  0x20
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/backentry.c b/ldap/servers/slapd/back-ldbm/backentry.c
dc8c34
index 52468ad..114c2df 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/backentry.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/backentry.c
dc8c34
@@ -52,6 +52,7 @@ backentry_free( struct backentry **bep )
dc8c34
 		return;
dc8c34
 	}
dc8c34
 	ep = *bep;
dc8c34
+	PR_ASSERT(ep->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE));
dc8c34
 	if ( ep->ep_entry != NULL ) {
dc8c34
 		slapi_entry_free( ep->ep_entry );
dc8c34
 	}
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
dc8c34
index 865f1ef..5510a9a 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/cache.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/cache.c
dc8c34
@@ -890,7 +890,7 @@ entrycache_remove_int(struct cache *cache, struct backentry *e)
dc8c34
         }
dc8c34
         else
dc8c34
         {
dc8c34
-            LOG("remove %d from id hash failed\n", e->ep_id, 0, 0);
dc8c34
+            LOG("remove %s (%d) from id hash failed\n", ndn, e->ep_id, 0);
dc8c34
         }
dc8c34
     }
dc8c34
 #ifdef UUIDCACHE_ON 
dc8c34
@@ -984,13 +984,19 @@ int cache_replace(struct cache *cache, void *oldptr, void *newptr)
dc8c34
 static int entrycache_replace(struct cache *cache, struct backentry *olde,
dc8c34
                               struct backentry *newe)
dc8c34
 {
dc8c34
-    int found;
dc8c34
+    int found = 0;
dc8c34
+    int found_in_dn = 0;
dc8c34
+    int found_in_id = 0;
dc8c34
+#ifdef UUIDCACHE_ON
dc8c34
+    int found_in_uuid = 0;
dc8c34
+#endif
dc8c34
     const char *oldndn;
dc8c34
     const char *newndn;
dc8c34
 #ifdef UUIDCACHE_ON 
dc8c34
     const char *olduuid;
dc8c34
     const char *newuuid;
dc8c34
 #endif
dc8c34
+    struct backentry *alte = NULL;
dc8c34
 
dc8c34
     LOG("=> entrycache_replace (%s) -> (%s)\n", backentry_get_ndn(olde),
dc8c34
         backentry_get_ndn(newe), 0);
dc8c34
@@ -1013,31 +1019,21 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
dc8c34
      * cache tables, operation error 
dc8c34
      */
dc8c34
     if ( (olde->ep_state & ENTRY_STATE_NOTINCACHE) == 0 ) {
dc8c34
-        int found_in_dn = remove_hash(cache->c_dntable, (void *)oldndn, strlen(oldndn));
dc8c34
-        int found_in_id = remove_hash(cache->c_idtable, &(olde->ep_id), sizeof(ID));
dc8c34
+        found_in_dn = remove_hash(cache->c_dntable, (void *)oldndn, strlen(oldndn));
dc8c34
+        found_in_id = remove_hash(cache->c_idtable, &(olde->ep_id), sizeof(ID));
dc8c34
 #ifdef UUIDCACHE_ON
dc8c34
-        int found_in_uuid = remove_hash(cache->c_uuidtable, (void *)olduuid, strlen(olduuid));
dc8c34
+        found_in_uuid = remove_hash(cache->c_uuidtable, (void *)olduuid, strlen(olduuid));
dc8c34
 #endif
dc8c34
         found = found_in_dn && found_in_id;
dc8c34
 #ifdef UUIDCACHE_ON
dc8c34
         found = found && found_in_uuid;
dc8c34
 #endif
dc8c34
-        if (!found) {
dc8c34
-#ifdef UUIDCACHE_ON
dc8c34
-            LOG("entry cache replace: cache index tables out of sync - found dn [%d] id [%d] uuid [%d]\n",
dc8c34
-                found_in_dn, found_in_id, found_in_uuid);
dc8c34
-#else
dc8c34
-            LOG("entry cache replace: cache index tables out of sync - found dn [%d] id [%d]\n",
dc8c34
-                found_in_dn, found_in_id, 0);
dc8c34
-#endif
dc8c34
-            PR_Unlock(cache->c_mutex);
dc8c34
-            return 1;
dc8c34
-        }
dc8c34
     }
dc8c34
-    if (! entry_same_dn(newe, (void *)oldndn) &&
dc8c34
-         (newe->ep_state & ENTRY_STATE_NOTINCACHE) == 0) {
dc8c34
-        /* if we're doing a modrdn, the new entry can be in the dn table
dc8c34
-         * already, so we need to remove that too.
dc8c34
+    /* If fails, we have to make sure the both entires are removed from the cache,
dc8c34
+     * otherwise, we have no idea what's left in the cache or not... */
dc8c34
+    if (!entry_same_dn(newe, (void *)oldndn) && (newe->ep_state & ENTRY_STATE_NOTINCACHE) == 0) {
dc8c34
+        /* if we're doing a modrdn or turning an entry to a tombstone,
dc8c34
+         * the new entry can be in the dn table already, so we need to remove that too.
dc8c34
          */
dc8c34
         if (remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)))
dc8c34
         {
dc8c34
@@ -1046,20 +1042,44 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
dc8c34
             LOG("entry cache replace remove entry size %lu\n", newe->ep_size, 0, 0);
dc8c34
         }
dc8c34
     }
dc8c34
-
dc8c34
+    /* 
dc8c34
+     * The old entry could have been "removed" between the add and this replace,
dc8c34
+     * The entry is NOT freed, but NOT in the dn hash.
dc8c34
+     * which could happen since the entry is not necessarily locked.
dc8c34
+     * This is ok.
dc8c34
+     */
dc8c34
+    olde->ep_state = ENTRY_STATE_DELETED; /* olde is removed from the cache, so set DELETED here. */
dc8c34
+    if (!found) {
dc8c34
+        if (olde->ep_state & ENTRY_STATE_DELETED) {
dc8c34
+            LOG("entry cache replace (%s): cache index tables out of sync - found dn [%d] id [%d]; but the entry is alreay deleted.\n",
dc8c34
+                oldndn, found_in_dn, found_in_id);
dc8c34
+        } else {
dc8c34
+#ifdef UUIDCACHE_ON
dc8c34
+            LOG("entry cache replace: cache index tables out of sync - found dn [%d] id [%d] uuid [%d]\n",
dc8c34
+                found_in_dn, found_in_id, found_in_uuid);
dc8c34
+#else
dc8c34
+            LOG("entry cache replace (%s): cache index tables out of sync - found dn [%d] id [%d]\n",
dc8c34
+                oldndn, found_in_dn, found_in_id);
dc8c34
+#endif
dc8c34
+            PR_Unlock(cache->c_mutex);
dc8c34
+            return 1;
dc8c34
+        }
dc8c34
+    }
dc8c34
     /* now, add the new entry to the hashtables */
dc8c34
     /* (probably don't need such extensive error handling, once this has been
dc8c34
      * tested enough that we believe it works.)
dc8c34
      */
dc8c34
-    if (!add_hash(cache->c_dntable, (void *)newndn, strlen(newndn), newe, NULL)) {
dc8c34
-       LOG("entry cache replace: can't add dn\n", 0, 0, 0);
dc8c34
+    if (!add_hash(cache->c_dntable, (void *)newndn, strlen(newndn), newe, (void **)&alte)) {
dc8c34
+       LOG("entry cache replace (%s): can't add to dn table (returned %s)\n", 
dc8c34
+           newndn, alte?slapi_entry_get_dn(alte->ep_entry):"none", 0);
dc8c34
        PR_Unlock(cache->c_mutex);
dc8c34
        return 1;
dc8c34
     }
dc8c34
-    if (!add_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID), newe, NULL)) {
dc8c34
-       LOG("entry cache replace: can't add id\n", 0, 0, 0);
dc8c34
+    if (!add_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID), newe, (void **)&alte)) {
dc8c34
+       LOG("entry cache replace (%s): can't add to id table (returned %s)\n", 
dc8c34
+           newndn, alte?slapi_entry_get_dn(alte->ep_entry):"none", 0);
dc8c34
        if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
dc8c34
-    	   LOG("entry cache replace: failed to remove dn table\n", 0, 0, 0);
dc8c34
+           LOG("entry cache replace: failed to remove dn table\n", 0, 0, 0);
dc8c34
        }
dc8c34
        PR_Unlock(cache->c_mutex);
dc8c34
        return 1;
dc8c34
@@ -1069,10 +1089,10 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
dc8c34
                        newe, NULL)) {
dc8c34
        LOG("entry cache replace: can't add uuid\n", 0, 0, 0);
dc8c34
        if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
dc8c34
-    	   LOG("entry cache replace: failed to remove dn table(uuid cache)\n", 0, 0, 0);
dc8c34
+           LOG("entry cache replace: failed to remove dn table(uuid cache)\n", 0, 0, 0);
dc8c34
        }
dc8c34
        if(remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID)) == 0){
dc8c34
-    	   LOG("entry cache replace: failed to remove id table(uuid cache)\n", 0, 0, 0);
dc8c34
+           LOG("entry cache replace: failed to remove id table(uuid cache)\n", 0, 0, 0);
dc8c34
        }
dc8c34
        PR_Unlock(cache->c_mutex);
dc8c34
        return 1;
dc8c34
@@ -1086,7 +1106,6 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
dc8c34
     } else if (newe->ep_size < olde->ep_size) {
dc8c34
         slapi_counter_subtract(cache->c_cursize, olde->ep_size - newe->ep_size);
dc8c34
     }
dc8c34
-    olde->ep_state = ENTRY_STATE_DELETED;
dc8c34
     newe->ep_state = 0;
dc8c34
     PR_Unlock(cache->c_mutex);
dc8c34
     LOG("<= entrycache_replace OK,  cache size now %lu cache count now %ld\n",
dc8c34
@@ -1269,7 +1288,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
dc8c34
     PR_Lock(cache->c_mutex);
dc8c34
     if (! add_hash(cache->c_dntable, (void *)ndn, strlen(ndn), e,
dc8c34
            (void **)&my_alt)) {
dc8c34
-        LOG("entry \"%s\" already in dn cache\n", backentry_get_ndn(e), 0, 0);
dc8c34
+        LOG("entry \"%s\" already in dn cache\n", ndn, 0, 0);
dc8c34
         /* add_hash filled in 'my_alt' if necessary */
dc8c34
         if (my_alt == e)
dc8c34
         {
dc8c34
@@ -1309,14 +1328,15 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
dc8c34
         {
dc8c34
             if (my_alt->ep_state & ENTRY_STATE_CREATING)
dc8c34
             {
dc8c34
-                LOG("the entry is reserved\n", 0, 0, 0);
dc8c34
+                LOG("the entry %s is reserved (ep_state: 0x%x, state: 0x%x\n", ndn, e->ep_state, state);
dc8c34
                 e->ep_state |= ENTRY_STATE_NOTINCACHE;
dc8c34
                 PR_Unlock(cache->c_mutex);
dc8c34
                 return -1;
dc8c34
             }
dc8c34
             else if (state != 0)
dc8c34
             {
dc8c34
-                LOG("the entry already exists. cannot reserve it.\n", 0, 0, 0);
dc8c34
+                LOG("the entry %s already exists. cannot reserve it. (ep_state: 0x%x, state: 0x%x\n",
dc8c34
+                    ndn, e->ep_state, state);
dc8c34
                 e->ep_state |= ENTRY_STATE_NOTINCACHE;
dc8c34
                 PR_Unlock(cache->c_mutex);
dc8c34
                 return -1;
dc8c34
@@ -1328,6 +1348,11 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
dc8c34
                     if ((*alt)->ep_refcnt == 0)
dc8c34
                         lru_delete(cache, (void *)*alt);
dc8c34
                     (*alt)->ep_refcnt++;
dc8c34
+                    LOG("the entry %s already exists.  returning existing entry %s (state: 0x%x)\n",
dc8c34
+                        ndn, backentry_get_ndn(my_alt), state);
dc8c34
+                } else {
dc8c34
+                    LOG("the entry %s already exists.  Not returning existing entry %s (state: 0x%x)\n",
dc8c34
+                        ndn, backentry_get_ndn(my_alt), state);
dc8c34
                 }
dc8c34
                 PR_Unlock(cache->c_mutex);
dc8c34
                 return 1;
dc8c34
@@ -1342,7 +1367,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
dc8c34
     if (state == 0) {
dc8c34
         /* neither of these should fail, or something is very wrong. */
dc8c34
         if (! add_hash(cache->c_idtable, &(e->ep_id), sizeof(ID), e, NULL)) {
dc8c34
-            LOG("entry %s already in id cache!\n", backentry_get_ndn(e), 0, 0);
dc8c34
+            LOG("entry %s already in id cache!\n", ndn, 0, 0);
dc8c34
             if (already_in) {
dc8c34
                 /* there's a bug in the implementatin of 'modify' and 'modrdn'
dc8c34
                  * that i'm working around here.  basically they do a
dc8c34
@@ -1364,10 +1389,12 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
dc8c34
                 return 0;
dc8c34
             }
dc8c34
             if(remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn)) == 0){
dc8c34
-            	LOG("entrycache_add_int: failed to remove dn table\n", 0, 0, 0);
dc8c34
+                LOG("entrycache_add_int: failed to remove %s from dn table\n", 0, 0, 0);
dc8c34
             }
dc8c34
             e->ep_state |= ENTRY_STATE_NOTINCACHE;
dc8c34
             PR_Unlock(cache->c_mutex);
dc8c34
+            LOG("entrycache_add_int: failed to add %s to cache (ep_state: %x, already_in: %d)\n",
dc8c34
+                ndn, e->ep_state, already_in);
dc8c34
             return -1;
dc8c34
         }
dc8c34
 #ifdef UUIDCACHE_ON 
dc8c34
@@ -1378,10 +1405,10 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
dc8c34
                 LOG("entry %s already in uuid cache!\n", backentry_get_ndn(e),
dc8c34
                             0, 0);
dc8c34
                 if(remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn)) == 0){
dc8c34
-                	LOG("entrycache_add_int: failed to remove dn table(uuid cache)\n", 0, 0, 0);
dc8c34
+                    LOG("entrycache_add_int: failed to remove dn table(uuid cache)\n", 0, 0, 0);
dc8c34
                 }
dc8c34
                 if(remove_hash(cache->c_idtable, &(e->ep_id), sizeof(ID)) == 0){
dc8c34
-                	LOG("entrycache_add_int: failed to remove id table(uuid cache)\n", 0, 0, 0);
dc8c34
+                    LOG("entrycache_add_int: failed to remove id table(uuid cache)\n", 0, 0, 0);
dc8c34
                 }
dc8c34
                 e->ep_state |= ENTRY_STATE_NOTINCACHE;
dc8c34
                 PR_Unlock(cache->c_mutex);
dc8c34
@@ -1487,8 +1514,8 @@ int cache_lock_entry(struct cache *cache, struct backentry *e)
dc8c34
            if (!e->ep_mutexp) {
dc8c34
                LOG("<= cache_lock_entry (DELETED)\n", 0, 0, 0);
dc8c34
                LDAPDebug1Arg(LDAP_DEBUG_ANY,
dc8c34
-                     "cache_lock_entry: failed to create a lock for %s\n",
dc8c34
-					 backentry_get_ndn(e));
dc8c34
+                             "cache_lock_entry: failed to create a lock for %s\n",
dc8c34
+                             backentry_get_ndn(e));
dc8c34
                LOG("<= cache_lock_entry (FAILED)\n", 0, 0, 0);
dc8c34
                return 1;
dc8c34
            }
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
index 0ade23c..b129307 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
@@ -79,7 +79,6 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	backend *be;
dc8c34
 	struct ldbminfo *li;
dc8c34
 	ldbm_instance *inst;
dc8c34
-	const char *dn = NULL;
dc8c34
 	Slapi_Entry	*e = NULL;
dc8c34
 	struct backentry *tombstoneentry = NULL;
dc8c34
 	struct backentry *addingentry = NULL;
dc8c34
@@ -118,6 +117,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	CSN *opcsn = NULL;
dc8c34
 	entry_address addr = {0};
dc8c34
 	int parent_switched = 0;
dc8c34
+	int noabort = 1;
dc8c34
 
dc8c34
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
dc8c34
 	slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e );
dc8c34
@@ -210,15 +210,14 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			slapi_pblock_get( pb, SLAPI_ADD_TARGET_SDN, &sdn );
dc8c34
 			if (NULL == sdn)
dc8c34
 			{
dc8c34
-				LDAPDebug0Args(LDAP_DEBUG_ANY,
dc8c34
-				               "ldbm_back_add: Null target dn\n");
dc8c34
+				LDAPDebug0Args(LDAP_DEBUG_ANY, "ldbm_back_add: FETCH_EXISTING_DN_ENTRY is set, but target dn is NULL.\n");
dc8c34
+				ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
 				goto error_return;
dc8c34
 			}
dc8c34
 
dc8c34
 			/* not need to check the dn syntax as this is a replicated op */
dc8c34
 			if(!is_replicated_operation){
dc8c34
-				dn = slapi_sdn_get_dn(sdn);
dc8c34
-				ldap_result_code = slapi_dn_syntax_check(pb, dn, 1);
dc8c34
+				ldap_result_code = slapi_dn_syntax_check(pb, slapi_sdn_get_dn(sdn), 1);
dc8c34
 				if (ldap_result_code)
dc8c34
 				{
dc8c34
 					ldap_result_code = LDAP_INVALID_DN_SYNTAX;
dc8c34
@@ -226,7 +225,10 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 					goto error_return;
dc8c34
 				}
dc8c34
 			}
dc8c34
-
dc8c34
+			/* 
dc8c34
+			 * If the parent is conflict, slapi_sdn_get_backend_parent does not support it.
dc8c34
+			 * That is, adding children to a conflict entry is not allowed.
dc8c34
+			 */
dc8c34
 			slapi_sdn_get_backend_parent(sdn, &parentsdn, pb->pb_backend);
dc8c34
 			/* Check if an entry with the intended DN already exists. */
dc8c34
 			done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_DN_ENTRY); /* Could be through this multiple times */
dc8c34
@@ -234,30 +236,27 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			addr.udn = NULL;
dc8c34
 			addr.uniqueid = NULL;
dc8c34
 			ldap_result_code= get_copy_of_entry(pb, &addr, &txn, SLAPI_ADD_EXISTING_DN_ENTRY, !is_replicated_operation);
dc8c34
-			if(ldap_result_code==LDAP_OPERATIONS_ERROR ||
dc8c34
-			   ldap_result_code==LDAP_INVALID_DN_SYNTAX)
dc8c34
-			{
dc8c34
-			    goto error_return;
dc8c34
+			if ((ldap_result_code == LDAP_OPERATIONS_ERROR) || (ldap_result_code==LDAP_INVALID_DN_SYNTAX)) {
dc8c34
+				goto error_return;
dc8c34
 			}
dc8c34
 		}
dc8c34
 		/* if we can find the parent by dn or uniqueid, and the operation has requested the parent
dc8c34
 		   then get it */
dc8c34
-		if(have_parent_address(&parentsdn, operation->o_params.p.p_add.parentuniqueid) &&
dc8c34
-		   slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY))
dc8c34
-		{
dc8c34
+		if (have_parent_address(&parentsdn, operation->o_params.p.p_add.parentuniqueid) &&
dc8c34
+		    slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY)) {
dc8c34
 			done_with_pblock_entry(pb,SLAPI_ADD_PARENT_ENTRY); /* Could be through this multiple times */
dc8c34
 			addr.sdn = &parentsdn;
dc8c34
 			addr.udn = NULL;
dc8c34
 			addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
dc8c34
-			ldap_result_code= get_copy_of_entry(pb, &addr, &txn, SLAPI_ADD_PARENT_ENTRY, !is_replicated_operation);
dc8c34
-			/* need to set parentsdn or parentuniqueid if either is not set? */
dc8c34
+			ldap_result_code = get_copy_of_entry(pb, &addr, &txn, SLAPI_ADD_PARENT_ENTRY, 
dc8c34
+			                                     !is_replicated_operation);
dc8c34
 		}
dc8c34
 
dc8c34
 		/* Call the Backend Pre Add plugins */
dc8c34
+		ldap_result_code = LDAP_SUCCESS;
dc8c34
 		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
-		rc= plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN);
dc8c34
-		if(rc==-1)
dc8c34
-		{
dc8c34
+		rc = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN);
dc8c34
+		if (rc == -1) {
dc8c34
 			int opreturn = 0;
dc8c34
 			/* 
dc8c34
 			 * Plugin indicated some kind of failure,
dc8c34
@@ -284,7 +283,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		 * the loop once again to get the new present state.
dc8c34
 		 */
dc8c34
 		/* JCMREPL - Warning: A Plugin could cause an infinite loop by always returning a result code that requires some action. */
dc8c34
-	}	
dc8c34
+	}
dc8c34
 
dc8c34
 	/*
dc8c34
 	 * Originally (in the U-M LDAP 3.3 code), there was a comment near this
dc8c34
@@ -309,10 +308,14 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				/* Set the parentuniqueid now */
dc8c34
 				operation->o_params.p.p_add.parentuniqueid = slapi_ch_strdup(slapi_entry_get_uniqueid(parententry->ep_entry));
dc8c34
 			}
dc8c34
-			if (slapi_sdn_isempty(&parentsdn)) {
dc8c34
+			if (slapi_sdn_isempty(&parentsdn) || 
dc8c34
+			    slapi_sdn_compare(&parentsdn, slapi_entry_get_sdn(parententry->ep_entry))) {
dc8c34
 				/* Set the parentsdn now */
dc8c34
 				slapi_sdn_set_dn_byval(&parentsdn, slapi_entry_get_dn_const(parententry->ep_entry));
dc8c34
 			}
dc8c34
+		} else {
dc8c34
+			LDAPDebug2Args(LDAP_DEBUG_BACKLDBM, "find_entry2modify_only returned NULL parententry pdn: %s, uniqueid: %s\n",
dc8c34
+			               slapi_sdn_get_dn(&parentsdn), addr.uniqueid?addr.uniqueid:"none");
dc8c34
 		}
dc8c34
 		modify_init(&parent_modify_c,parententry);
dc8c34
 	}
dc8c34
@@ -320,11 +323,39 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	/* Check if the entry we have been asked to add already exists */
dc8c34
 	{
dc8c34
 		Slapi_Entry *entry;
dc8c34
-		slapi_pblock_get( pb, SLAPI_ADD_EXISTING_DN_ENTRY, &entry);
dc8c34
-		if ( entry != NULL )
dc8c34
-		{
dc8c34
-			/* The entry already exists */ 
dc8c34
-			ldap_result_code= LDAP_ALREADY_EXISTS;
dc8c34
+		slapi_pblock_get(pb, SLAPI_ADD_EXISTING_DN_ENTRY, &entry);
dc8c34
+		if (entry) {
dc8c34
+			if (is_resurect_operation) {
dc8c34
+				Slapi_Entry *uniqentry;
dc8c34
+				slapi_pblock_get(pb, SLAPI_ADD_EXISTING_UNIQUEID_ENTRY, &uniqentry);
dc8c34
+				if (uniqentry == entry) { 
dc8c34
+					/* 
dc8c34
+					 * adding entry having the uniqueid exists.
dc8c34
+					 * No need to resurrect.
dc8c34
+					 */ 
dc8c34
+					ldap_result_code = LDAP_SUCCESS;
dc8c34
+				} else {
dc8c34
+					/* 
dc8c34
+					 * The entry having the DN already exists.
dc8c34
+					 * But the 
dc8c34
+					 */ 
dc8c34
+					if (uniqentry) {
dc8c34
+						if (PL_strcmp(slapi_entry_get_uniqueid(entry),
dc8c34
+						              slapi_entry_get_uniqueid(uniqentry))) {
dc8c34
+							/* Not match; conflict. */
dc8c34
+							ldap_result_code = LDAP_ALREADY_EXISTS;
dc8c34
+						} else {
dc8c34
+							/* Same entry; no need to resurrect. */
dc8c34
+							ldap_result_code = LDAP_SUCCESS;
dc8c34
+						}
dc8c34
+					} else {
dc8c34
+						ldap_result_code = LDAP_ALREADY_EXISTS;
dc8c34
+					}
dc8c34
+				}
dc8c34
+			} else {
dc8c34
+				/* The entry already exists */ 
dc8c34
+				ldap_result_code = LDAP_ALREADY_EXISTS;
dc8c34
+			}
dc8c34
 			goto error_return;
dc8c34
 		} 
dc8c34
 		else 
dc8c34
@@ -335,7 +366,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			 * entry we did match has a referral we should return
dc8c34
 			 * instead. we do this only if managedsait is not on.
dc8c34
 			 */
dc8c34
-			if ( !managedsait && !is_tombstone_operation )
dc8c34
+			if (!managedsait && !is_tombstone_operation && !is_resurect_operation)
dc8c34
 			{
dc8c34
 				int err= 0;
dc8c34
 				Slapi_DN ancestorsdn;
dc8c34
@@ -392,14 +423,14 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		if ( tombstoneentry==NULL )
dc8c34
 		{
dc8c34
 			ldap_result_code= -1;
dc8c34
-			goto error_return;	  /* error result sent by find_entry2modify() */
dc8c34
+			goto error_return;  /* error result sent by find_entry2modify() */
dc8c34
 		}
dc8c34
 		tombstone_in_cache = 1;
dc8c34
 
dc8c34
 		addingentry = backentry_dup( tombstoneentry );
dc8c34
 		if ( addingentry==NULL )
dc8c34
 		{
dc8c34
-			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+			ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
 		/*
dc8c34
@@ -411,17 +442,21 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		 */
dc8c34
 		if (NULL == sdn) {
dc8c34
 			LDAPDebug0Args(LDAP_DEBUG_ANY, "ldbm_back_add: Null target dn\n");
dc8c34
+			ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
-		dn = slapi_sdn_get_dn(sdn);
dc8c34
 		slapi_entry_set_sdn(addingentry->ep_entry, sdn); /* The DN is passed into the entry. */
dc8c34
+		/* not just e_sdn, e_rsdn needs to be updated. */
dc8c34
+		slapi_rdn_set_all_dn(slapi_entry_get_srdn(addingentry->ep_entry),
dc8c34
+		                     slapi_entry_get_dn_const(addingentry->ep_entry));
dc8c34
 		/* LPREPL: the DN is normalized...Somehow who should get a not normalized one */
dc8c34
 		addingentry->ep_id = slapi_entry_attr_get_ulong(addingentry->ep_entry,"entryid");
dc8c34
 		slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
dc8c34
 		slapi_entry_delete_string(addingentry->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
dc8c34
 		/* Now also remove the nscpEntryDN */
dc8c34
 		if (slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN) != 0){
dc8c34
-			LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Couldn't remove %s\n", dn, SLAPI_ATTR_NSCP_ENTRYDN, 0);
dc8c34
+			LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Couldn't remove %s\n", 
dc8c34
+			          slapi_sdn_get_dn(sdn), SLAPI_ATTR_NSCP_ENTRYDN, 0);
dc8c34
 		}
dc8c34
 		
dc8c34
 		/* And copy the reason from e */
dc8c34
@@ -429,7 +464,8 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		if (reason) {
dc8c34
 			if (!slapi_entry_attr_hasvalue(addingentry->ep_entry, "nsds5ReplConflict", reason)) {
dc8c34
 				slapi_entry_add_string(addingentry->ep_entry, "nsds5ReplConflict", reason);
dc8c34
-				LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Added Conflict reason %s\n", dn, reason, 0);
dc8c34
+				LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Added Conflict reason %s\n",
dc8c34
+				          slapi_sdn_get_dn(sdn), reason, 0);
dc8c34
 			}
dc8c34
 			slapi_ch_free((void **)&reason);
dc8c34
 		}
dc8c34
@@ -578,9 +614,8 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			Slapi_DN ancestorsdn;
dc8c34
 			struct backentry *ancestorentry;
dc8c34
 
dc8c34
-			LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
-				"parent does not exist, pdn = %s\n",
dc8c34
-				slapi_sdn_get_dn(&parentsdn), 0, 0 );
dc8c34
+			LDAPDebug1Arg(LDAP_DEBUG_BACKLDBM, "ldbm_add: Parent \"%s\" does not exist. "
dc8c34
+			              "It might be a conflict entry.\n", slapi_sdn_get_dn(&parentsdn));
dc8c34
 
dc8c34
 			slapi_sdn_init(&ancestorsdn);
dc8c34
 			ancestorentry = dn2ancestor(be, &parentsdn, &ancestorsdn, &txn, &err );
dc8c34
@@ -591,22 +626,38 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			slapi_sdn_done(&ancestorsdn);
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
-		ldap_result_code = plugin_call_acl_plugin (pb, e, NULL, NULL, SLAPI_ACL_ADD, 
dc8c34
-						ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
dc8c34
+		ldap_result_code = plugin_call_acl_plugin(pb, e, NULL, NULL, SLAPI_ACL_ADD, 
dc8c34
+		                                          ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
dc8c34
 		if ( ldap_result_code != LDAP_SUCCESS )
dc8c34
 		{
dc8c34
-			LDAPDebug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 );
dc8c34
+			LDAPDebug1Arg(LDAP_DEBUG_TRACE, "no access to parent, pdn = %s\n",
dc8c34
+			              slapi_sdn_get_dn(&parentsdn));
dc8c34
 			ldap_result_message= errbuf;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
 		pid = parententry->ep_id;
dc8c34
+
dc8c34
+		/* We may need to adjust the DN since parent could be a resrected conflict entry... */
dc8c34
+		if (!slapi_sdn_isparent(slapi_entry_get_sdn_const(parententry->ep_entry),
dc8c34
+		                        slapi_entry_get_sdn_const(addingentry->ep_entry))) {
dc8c34
+			Slapi_DN adjustedsdn = {0};
dc8c34
+			char *adjusteddn = slapi_ch_smprintf("%s,%s", 
dc8c34
+			                                    slapi_entry_get_rdn_const(addingentry->ep_entry),
dc8c34
+			                                    slapi_entry_get_dn_const(parententry->ep_entry));
dc8c34
+			LDAPDebug2Args(LDAP_DEBUG_BACKLDBM, "ldbm_add: adjusting dn: %s --> %s\n",
dc8c34
+			               slapi_entry_get_dn(addingentry->ep_entry), adjusteddn);
dc8c34
+			slapi_sdn_set_normdn_passin(&adjustedsdn, adjusteddn);
dc8c34
+			slapi_entry_set_sdn(addingentry->ep_entry, &adjustedsdn);
dc8c34
+			/* not just e_sdn, e_rsdn needs to be updated. */
dc8c34
+			slapi_rdn_set_all_dn(slapi_entry_get_srdn(addingentry->ep_entry), adjusteddn);
dc8c34
+			slapi_sdn_done(&adjustedsdn);
dc8c34
+		}
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{	/* no parent */
dc8c34
-		if ( !isroot && !is_replicated_operation)
dc8c34
+		if (!isroot && !is_replicated_operation)
dc8c34
 		{
dc8c34
-			LDAPDebug( LDAP_DEBUG_TRACE, "no parent & not root\n",
dc8c34
-				0, 0, 0 );
dc8c34
+			LDAPDebug0Args(LDAP_DEBUG_TRACE, "no parent & not root\n");
dc8c34
 			ldap_result_code= LDAP_INSUFFICIENT_ACCESS;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
@@ -635,11 +686,12 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	 * operational attributes to ensure that the cache is sized correctly. */
dc8c34
 	if ( cache_add_tentative( &inst->inst_cache, addingentry, NULL )!= 0 )
dc8c34
 	{
dc8c34
-		LDAPDebug( LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected\n", 0, 0, 0 );
dc8c34
+		LDAPDebug1Arg(LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected: %s\n",
dc8c34
+		              slapi_entry_get_dn_const(addingentry->ep_entry));
dc8c34
 		ldap_result_code= LDAP_ALREADY_EXISTS;
dc8c34
 		goto error_return;
dc8c34
 	}
dc8c34
-	addingentry_in_cache= 1;
dc8c34
+	addingentry_in_cache = 1;
dc8c34
 
dc8c34
 	/*
dc8c34
 	 * Before we add the entry, find out if the syntax of the aci
dc8c34
@@ -647,7 +699,8 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	 * the entry if the syntax is incorrect.
dc8c34
 	 */
dc8c34
 	if ( plugin_call_acl_verify_syntax (pb, addingentry->ep_entry, &errbuf) != 0 ) {
dc8c34
-		LDAPDebug( LDAP_DEBUG_TRACE, "ACL syntax error\n", 0,0,0);
dc8c34
+		LDAPDebug1Arg(LDAP_DEBUG_TRACE, "ACL syntax error: %s\n",
dc8c34
+		              slapi_entry_get_dn_const(addingentry->ep_entry));
dc8c34
 		ldap_result_code= LDAP_INVALID_SYNTAX;
dc8c34
 		ldap_result_message= errbuf;
dc8c34
 		goto error_return;
dc8c34
@@ -656,12 +709,15 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	/* Having decided that we're really going to do the operation, let's modify 
dc8c34
 	   the in-memory state of the parent to reflect the new child (update
dc8c34
 	   subordinate count specifically */
dc8c34
-	if (NULL != parententry)
dc8c34
+	if (parententry)
dc8c34
 	{
dc8c34
 		retval = parent_update_on_childchange(&parent_modify_c,
dc8c34
-		                                      PARENTUPDATE_ADD, NULL);
dc8c34
+		                                      is_resurect_operation?PARENTUPDATE_RESURECT:PARENTUPDATE_ADD,
dc8c34
+		                                      NULL);
dc8c34
 		/* The modify context now contains info needed later */
dc8c34
-		if (0 != retval) {
dc8c34
+		if (retval) {
dc8c34
+			LDAPDebug2Args(LDAP_DEBUG_BACKLDBM, "parent_update_on_childchange: %s, rc=%d\n",
dc8c34
+			               slapi_entry_get_dn_const(addingentry->ep_entry), retval);
dc8c34
 			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
@@ -681,11 +737,16 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
dc8c34
 		if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) {
dc8c34
 			dblayer_txn_abort(li,&txn);
dc8c34
+			noabort = 1;
dc8c34
 			slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
dc8c34
 
dc8c34
 			if (addingentry_in_cache) {
dc8c34
 				/* addingentry is in cache.  Remove it once. */
dc8c34
-				CACHE_REMOVE(&inst->inst_cache, addingentry);
dc8c34
+				retval = CACHE_REMOVE(&inst->inst_cache, addingentry);
dc8c34
+				if (retval) {
dc8c34
+					LDAPDebug1Arg(LDAP_DEBUG_CACHE, "ldbm_add: cache_remove %s failed.\n",
dc8c34
+					              slapi_entry_get_dn_const(addingentry->ep_entry));
dc8c34
+				}
dc8c34
 				CACHE_RETURN(&inst->inst_cache, &addingentry);
dc8c34
 			} else {
dc8c34
 				backentry_free(&addingentry);
dc8c34
@@ -698,11 +759,11 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			}
dc8c34
 			if (addingentry_in_cache) {
dc8c34
 				/* Adding the resetted addingentry to the cache. */
dc8c34
-				if (cache_add_tentative(&inst->inst_cache,
dc8c34
-				                        addingentry, NULL) != 0) {
dc8c34
-					LDAPDebug0Args(LDAP_DEBUG_CACHE,
dc8c34
-					              "cache_add_tentative concurrency detected\n");
dc8c34
+				if (cache_add_tentative(&inst->inst_cache, addingentry, NULL) != 0) {
dc8c34
+					LDAPDebug1Arg(LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected: %s\n",
dc8c34
+					              slapi_entry_get_dn_const(addingentry->ep_entry));
dc8c34
 					ldap_result_code = LDAP_ALREADY_EXISTS;
dc8c34
+					addingentry_in_cache = 0;
dc8c34
 					goto error_return;
dc8c34
 				}
dc8c34
 			}
dc8c34
@@ -732,6 +793,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
 			goto error_return; 
dc8c34
 		}
dc8c34
+		noabort = 0;
dc8c34
 
dc8c34
 		/* stash the transaction for plugins */
dc8c34
 		slapi_pblock_set(pb, SLAPI_TXN, txn.back_txn_txn);
dc8c34
@@ -739,14 +801,12 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		/* call the transaction pre add plugins just after creating the transaction */
dc8c34
 		if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN))) {
dc8c34
 			int opreturn = 0;
dc8c34
-			LDAPDebug1Arg( LDAP_DEBUG_TRACE, "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin "
dc8c34
-				       "returned error code %d\n", retval );
dc8c34
+			LDAPDebug1Arg(LDAP_DEBUG_TRACE, "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin "
dc8c34
+			              "returned error code %d\n", retval );
dc8c34
 			if (!ldap_result_code) {
dc8c34
 				slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 			}
dc8c34
 			if (!ldap_result_code) {
dc8c34
-				LDAPDebug0Args( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin "
dc8c34
-						"returned error but did not setSLAPI_RESULT_CODE \n" );
dc8c34
 				ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
 				slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 			}
dc8c34
@@ -754,6 +814,8 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			if (!opreturn) {
dc8c34
 				slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
dc8c34
 			}
dc8c34
+			LDAPDebug1Arg(LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin failed: %d",
dc8c34
+			              ldap_result_code ? ldap_result_code : retval);
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
 
dc8c34
@@ -764,9 +826,10 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			/* Retry txn */
dc8c34
 			continue;
dc8c34
 		}
dc8c34
-		if (retval != 0) {
dc8c34
-			LDAPDebug( LDAP_DEBUG_TRACE, "id2entry_add failed, err=%d %s\n",
dc8c34
-				   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
+		if (retval) {
dc8c34
+			LDAPDebug(LDAP_DEBUG_TRACE, "id2entry_add(%s) failed, err=%d %s\n",
dc8c34
+			          slapi_entry_get_dn_const(addingentry->ep_entry),
dc8c34
+			          retval, (msg = dblayer_strerror( retval )) ? msg : "");
dc8c34
 			ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 			if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 				disk_full = 1;
dc8c34
@@ -782,11 +845,11 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
-			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE, "add 1 BAD, err=%d %s\n",
dc8c34
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
-				ADD_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+			if (retval) {
dc8c34
+				LDAPDebug(LDAP_DEBUG_TRACE, "index_addordel_string TOMBSTONE (%s), err=%d %s\n",
dc8c34
+				          slapi_entry_get_dn_const(addingentry->ep_entry),
dc8c34
+				          retval, (msg = dblayer_strerror( retval )) ? msg : "");
dc8c34
+				ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 					disk_full = 1;
dc8c34
 					goto diskfull_return;
dc8c34
@@ -800,10 +863,10 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE, "add 2 BAD, err=%d %s\n",
dc8c34
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
-				ADD_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+				LDAPDebug(LDAP_DEBUG_TRACE, "index_addordel_string UNIQUEID (%s), err=%d %s\n",
dc8c34
+				          slapi_entry_get_dn_const(addingentry->ep_entry),
dc8c34
+				          retval, (msg = dblayer_strerror( retval )) ? msg : "");
dc8c34
+				ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 					disk_full = 1;
dc8c34
 					goto diskfull_return;
dc8c34
@@ -821,17 +884,29 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE, "add 3 BAD, err=%d %s\n",
dc8c34
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
-				ADD_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+				LDAPDebug(LDAP_DEBUG_TRACE, "index_addordel_string ENTRYDN (%s), err=%d %s\n",
dc8c34
+				          slapi_entry_get_dn_const(addingentry->ep_entry),
dc8c34
+				          retval, (msg = dblayer_strerror( retval )) ? msg : "");
dc8c34
+				ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 					disk_full = 1;
dc8c34
 					goto diskfull_return;
dc8c34
 				}
dc8c34
 				goto error_return; 
dc8c34
 			}
dc8c34
-		} 
dc8c34
+			/* Need to delete the entryrdn index of the resurrected tombstone... */
dc8c34
+			if (entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+				if (tombstoneentry) {
dc8c34
+					retval = entryrdn_index_entry(be, tombstoneentry, BE_INDEX_DEL, &txn);
dc8c34
+					if (retval) {
dc8c34
+						LDAPDebug(LDAP_DEBUG_ANY, "Resurrecting %s: failed to remove entryrdn index, err=%d %s\n",
dc8c34
+						          slapi_entry_get_dn_const(tombstoneentry->ep_entry),
dc8c34
+						          retval, (msg = dblayer_strerror( retval )) ? msg : "");
dc8c34
+						goto error_return; 
dc8c34
+					}
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
 		if (is_tombstone_operation)
dc8c34
 		{
dc8c34
 			retval = index_addordel_entry( be, addingentry, BE_INDEX_ADD | BE_INDEX_TOMBSTONE, &txn );
dc8c34
@@ -846,9 +921,9 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			/* retry txn */
dc8c34
 			continue;
dc8c34
 		}
dc8c34
-		if (retval != 0) {
dc8c34
-			LDAPDebug( LDAP_DEBUG_ANY, "add: attempt to index %lu failed\n",
dc8c34
-								   (u_long)addingentry->ep_id, 0, 0 );
dc8c34
+		if (retval) {
dc8c34
+			LDAPDebug2Args(LDAP_DEBUG_ANY, "add: attempt to index %lu failed; rc=%d\n",
dc8c34
+			               (u_long)addingentry->ep_id, retval);
dc8c34
 			ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 			if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 				disk_full = 1;
dc8c34
@@ -865,11 +940,10 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
-			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE, "add 1 BAD, err=%d %s\n",
dc8c34
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
-				ADD_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+			if (retval) {
dc8c34
+				LDAPDebug(LDAP_DEBUG_BACKLDBM, "modify_update_all: %s (%lu) failed; rc=%d\n",
dc8c34
+				          slapi_entry_get_dn(addingentry->ep_entry), (u_long)addingentry->ep_id, retval);
dc8c34
+				ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 					disk_full = 1;
dc8c34
 					goto diskfull_return;
dc8c34
@@ -884,17 +958,16 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		{
dc8c34
 			retval= vlv_update_all_indexes(&txn, be, pb, NULL, addingentry);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
-								"add DEADLOCK vlv_update_index\n", 0, 0, 0 );
dc8c34
+				LDAPDebug(LDAP_DEBUG_ARGS,
dc8c34
+				          "add DEADLOCK vlv_update_index\n", 0, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
-			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
-					"vlv_update_index failed, err=%d %s\n",
dc8c34
-				   	retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
-				ADD_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+			if (retval) {
dc8c34
+				LDAPDebug2Args(LDAP_DEBUG_TRACE,
dc8c34
+				               "vlv_update_index failed, err=%d %s\n",
dc8c34
+				               retval, (msg = dblayer_strerror( retval )) ? msg : "");
dc8c34
+				ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 					disk_full = 1;
dc8c34
 					goto diskfull_return;
dc8c34
@@ -940,7 +1013,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 	if (retry_count == RETRY_TIMES) {
dc8c34
 		/* Failed */
dc8c34
 		LDAPDebug( LDAP_DEBUG_ANY, "Retry count exceeded in add\n", 0, 0, 0 );
dc8c34
-   		ldap_result_code= LDAP_BUSY;
dc8c34
+		ldap_result_code= LDAP_BUSY;
dc8c34
 		goto error_return;
dc8c34
 	}
dc8c34
 
dc8c34
@@ -956,33 +1029,49 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		/*
dc8c34
 		 * We can now switch the tombstone entry with the real entry.
dc8c34
 		 */
dc8c34
-		if (cache_replace( &inst->inst_cache, tombstoneentry, addingentry ) != 0 )
dc8c34
-		{
dc8c34
+		retval = cache_replace(&inst->inst_cache, tombstoneentry, addingentry);
dc8c34
+		if (retval) {
dc8c34
 			/* This happens if the dn of addingentry already exists */
dc8c34
-			cache_unlock_entry( &inst->inst_cache, tombstoneentry );
dc8c34
 			ADD_SET_ERROR(ldap_result_code, LDAP_ALREADY_EXISTS, retry_count);
dc8c34
+			LDAPDebug2Args(LDAP_DEBUG_CACHE, "ldap_add: cache_replace concurrency detected: %s (rc: %d)\n",
dc8c34
+			               slapi_entry_get_dn_const(addingentry->ep_entry), retval);
dc8c34
+			retval = -1;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
+		if (addingentry_in_cache) { /* decrease the refcnt added by tentative */
dc8c34
+			CACHE_RETURN( &inst->inst_cache, &addingentry );
dc8c34
+		}
dc8c34
+		addingentry_in_cache = 1; /* reset it to make it sure... */
dc8c34
 		/*
dc8c34
 		 * The tombstone was locked down in the cache... we can
dc8c34
 		 * get rid of the entry in the cache now.
dc8c34
+		 * We cannot expect tombstoneentry exists from now on.
dc8c34
 		 */
dc8c34
+		if (entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+			/* since the op was successful, delete the tombstone dn from the dn cache */
dc8c34
+			struct backdn *bdn = dncache_find_id(&inst->inst_dncache,
dc8c34
+			                                     tombstoneentry->ep_id);
dc8c34
+			if (bdn) { /* in the dncache, remove it. */
dc8c34
+				CACHE_REMOVE(&inst->inst_dncache, bdn);
dc8c34
+				CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+			}
dc8c34
+		}
dc8c34
 		cache_unlock_entry( &inst->inst_cache, tombstoneentry );
dc8c34
 		CACHE_RETURN( &inst->inst_cache, &tombstoneentry );
dc8c34
-		tombstone_in_cache = 0; /* deleted */
dc8c34
+		tombstone_in_cache = 0;
dc8c34
 	}
dc8c34
 	if (parent_found)
dc8c34
 	{
dc8c34
 		/* switch the parent entry copy into play */
dc8c34
-		modify_switch_entries( &parent_modify_c,be);
dc8c34
+		modify_switch_entries(&parent_modify_c,be);
dc8c34
 		parent_switched = 1;
dc8c34
 	}
dc8c34
 
dc8c34
 	if (ruv_c_init) {
dc8c34
 		if (modify_switch_entries(&ruv_c, be) != 0 ) {
dc8c34
 			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
-			LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
-				"ldbm_back_add: modify_switch_entries failed\n", 0, 0, 0);
dc8c34
+			LDAPDebug0Args(LDAP_DEBUG_ANY,
dc8c34
+			               "ldbm_back_add: modify_switch_entries failed\n");
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
 	}
dc8c34
@@ -996,8 +1085,6 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 		}
dc8c34
 		if (!ldap_result_code) {
dc8c34
-			LDAPDebug0Args( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_POST_ADD_FN plugin "
dc8c34
-					"returned error but did not set SLAPI_RESULT_CODE\n" );
dc8c34
 			ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
 			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 		}
dc8c34
@@ -1020,6 +1107,7 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		}
dc8c34
 		goto error_return; 
dc8c34
 	}
dc8c34
+	noabort = 1;
dc8c34
 
dc8c34
 	rc= 0;
dc8c34
 	goto common_return;
dc8c34
@@ -1029,21 +1117,20 @@ error_return:
dc8c34
 	{
dc8c34
 		next_id_return( be, addingentry->ep_id );
dc8c34
 	}
dc8c34
-	if ( NULL != addingentry )
dc8c34
+	if ( addingentry )
dc8c34
 	{
dc8c34
 		if ( addingentry_in_cache )
dc8c34
 		{
dc8c34
 			CACHE_REMOVE(&inst->inst_cache, addingentry);
dc8c34
-			addingentry_in_cache = 0;
dc8c34
 		}
dc8c34
-		backentry_clear_entry(addingentry); /* e is released in the frontend */
dc8c34
-		backentry_free( &addingentry ); /* release the backend wrapper, here */
dc8c34
-	}
dc8c34
-	if(tombstone_in_cache)
dc8c34
-	{
dc8c34
-		CACHE_RETURN(&inst->inst_cache, &tombstoneentry);
dc8c34
+		else
dc8c34
+		{
dc8c34
+			if (!is_resurect_operation) { /* if resurect, tombstoneentry is dupped. */
dc8c34
+				backentry_clear_entry(addingentry); /* e is released in the frontend */
dc8c34
+			}
dc8c34
+			backentry_free( &addingentry ); /* release the backend wrapper, here */
dc8c34
+		}
dc8c34
 	}
dc8c34
-
dc8c34
 	if (rc == DB_RUNRECOVERY) {
dc8c34
 		dblayer_remember_disk_filled(li);
dc8c34
 		ldbm_nasty("Add",80,rc);
dc8c34
@@ -1063,7 +1150,7 @@ error_return:
dc8c34
 
dc8c34
 diskfull_return:
dc8c34
 	if (disk_full) {
dc8c34
-		rc= return_on_disk_full(li);
dc8c34
+		rc = return_on_disk_full(li);
dc8c34
 	} else {
dc8c34
 		/* It is safer not to abort when the transaction is not started. */
dc8c34
 		if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) {
dc8c34
@@ -1096,39 +1183,44 @@ diskfull_return:
dc8c34
 				}
dc8c34
 			}
dc8c34
 
dc8c34
-			dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
dc8c34
+			if (!noabort) {
dc8c34
+				dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
dc8c34
+			}
dc8c34
 			/* txn is no longer valid - reset the txn pointer to the parent */
dc8c34
 			slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
dc8c34
 		}
dc8c34
-		rc= SLAPI_FAIL_GENERAL;
dc8c34
+		rc = SLAPI_FAIL_GENERAL;
dc8c34
 	}
dc8c34
 	
dc8c34
 common_return:
dc8c34
-    if (addingentry_in_cache && addingentry)
dc8c34
-	{
dc8c34
-        if (entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
-            /* since adding the entry to the entry cache was successful,
dc8c34
-             * let's add the dn to dncache, if not yet done. */
dc8c34
-            struct backdn *bdn = dncache_find_id(&inst->inst_dncache,
dc8c34
-                                                 addingentry->ep_id);
dc8c34
-            if (bdn) { /* already in the dncache */
dc8c34
-                CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
-            } else { /* not in the dncache yet */
dc8c34
-                Slapi_DN *addingsdn = 
dc8c34
-                      slapi_sdn_dup(slapi_entry_get_sdn(addingentry->ep_entry));
dc8c34
-                if (addingsdn) {
dc8c34
-                    bdn = backdn_init(addingsdn, addingentry->ep_id, 0);
dc8c34
-                    if (bdn) {
dc8c34
-                        CACHE_ADD( &inst->inst_dncache, bdn, NULL );
dc8c34
-                        CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
-                        slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_add",
dc8c34
-                                                    "set %s to dn cache\n", dn);
dc8c34
-                    }
dc8c34
-                }
dc8c34
-            }
dc8c34
-        }
dc8c34
-        CACHE_RETURN( &inst->inst_cache, &addingentry );
dc8c34
-    }
dc8c34
+	if (inst) {
dc8c34
+		if(tombstone_in_cache && tombstoneentry) {
dc8c34
+			cache_unlock_entry(&inst->inst_cache, tombstoneentry);
dc8c34
+			CACHE_RETURN(&inst->inst_cache, &tombstoneentry);
dc8c34
+		}
dc8c34
+	}
dc8c34
+	if (addingentry_in_cache && addingentry) {
dc8c34
+		if ((0 == retval) && entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+			/* since the op was successful, add the addingentry's dn to the dn cache */
dc8c34
+			struct backdn *bdn = dncache_find_id(&inst->inst_dncache,
dc8c34
+			                                     addingentry->ep_id);
dc8c34
+			if (bdn) { /* already in the dncache */
dc8c34
+				CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+			} else { /* not in the dncache yet */
dc8c34
+				Slapi_DN *addingsdn = slapi_sdn_dup(slapi_entry_get_sdn(addingentry->ep_entry));
dc8c34
+				if (addingsdn) {
dc8c34
+					bdn = backdn_init(addingsdn, addingentry->ep_id, 0);
dc8c34
+					if (bdn) {
dc8c34
+						CACHE_ADD( &inst->inst_dncache, bdn, NULL );
dc8c34
+						CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+						slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_add",
dc8c34
+						                "set %s to dn cache\n", slapi_sdn_get_dn(sdn));
dc8c34
+					}
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
+		CACHE_RETURN( &inst->inst_cache, &addingentry );
dc8c34
+	}
dc8c34
 	/* bepost op needs to know this result */
dc8c34
 	slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 	/* JCMREPL - The bepostop is called even if the operation fails. */
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
index c9ce70f..32feeb1 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
@@ -91,6 +91,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 									/* replication, we must create a new tombstone entry	*/
dc8c34
 	int tombstone_in_cache = 0;
dc8c34
 	int e_in_cache = 0;
dc8c34
+	int remove_e_from_cache = 0;
dc8c34
 	entry_address *addr;
dc8c34
 	int addordel_flags = 0; /* passed to index_addordel */
dc8c34
 	char *entryusn_str = NULL;
dc8c34
@@ -178,18 +179,29 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 	}
dc8c34
 
dc8c34
 	/* find and lock the entry we are about to modify */
dc8c34
+	/* 
dc8c34
+	 * A corner case: 
dc8c34
+	 * If a conflict occurred in a MMR topology, a replicated delete 
dc8c34
+	 * op from another master could target a conflict entry; while the
dc8c34
+	 * corresponding entry on this server could have been already 
dc8c34
+	 * deleted.  That is, the entry 'e' found with "addr" is a tomb-
dc8c34
+	 * stone.  If it is the case, we need to back off.
dc8c34
+	 */
dc8c34
 	if ( (e = find_entry2modify( pb, be, addr, &txn )) == NULL )
dc8c34
 	{
dc8c34
 		ldap_result_code= LDAP_NO_SUCH_OBJECT; 
dc8c34
 		/* retval is -1 */
dc8c34
+		LDAPDebug0Args(LDAP_DEBUG_BACKLDBM, "ldbm_back_delete: Deleting entry is already deleted.\n");
dc8c34
 		goto error_return; /* error result sent by find_entry2modify() */
dc8c34
 	}
dc8c34
 	e_in_cache = 1; /* e is cached */
dc8c34
 
dc8c34
-	if ( slapi_entry_has_children( e->ep_entry ) )
dc8c34
-	{
dc8c34
+	retval = slapi_entry_has_children(e->ep_entry);
dc8c34
+	if (retval) {
dc8c34
 		ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
dc8c34
-		/* retval is -1 */
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete", "Deleting entry %s has %d children.\n", 
dc8c34
+		                slapi_entry_get_dn(e->ep_entry), retval);
dc8c34
+		retval = -1;
dc8c34
 		goto error_return;
dc8c34
 	}
dc8c34
 
dc8c34
@@ -221,7 +233,17 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			 * Plugin indicated some kind of failure,
dc8c34
 			 * or that this Operation became a No-Op.
dc8c34
 			 */
dc8c34
+			slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 			if (!ldap_result_code) {
dc8c34
+				if (LDAP_ALREADY_EXISTS == ldap_result_code) {
dc8c34
+					/* 
dc8c34
+					 * The target entry is already a tombstone.
dc8c34
+					 * We need to treat this as a success,
dc8c34
+					 * but we need to remove the entry e from the entry cache.
dc8c34
+					 */
dc8c34
+					remove_e_from_cache = 1;
dc8c34
+					ldap_result_code = LDAP_SUCCESS;
dc8c34
+				}
dc8c34
 				slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
dc8c34
 			}
dc8c34
 			/* restore original entry so the front-end delete code can free it */
dc8c34
@@ -233,8 +255,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
 		/* the flag could be set in a preop plugin (e.g., USN) */
dc8c34
-		delete_tombstone_entry = operation_is_flag_set(operation,
dc8c34
-									OP_FLAG_TOMBSTONE_ENTRY);
dc8c34
+		delete_tombstone_entry = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_ENTRY);
dc8c34
 	}
dc8c34
 
dc8c34
 	/*
dc8c34
@@ -370,13 +391,15 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 		}
dc8c34
 		if (NULL == parent) {
dc8c34
 			entry_address parent_addr;
dc8c34
-
dc8c34
+			if (is_tombstone_entry) {
dc8c34
+				parent_addr.uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
dc8c34
+			} else {
dc8c34
+				parent_addr.uniqueid = NULL;
dc8c34
+			}
dc8c34
 			parent_addr.sdn = &parentsdn;
dc8c34
-			parent_addr.uniqueid = NULL;
dc8c34
-			parent = find_entry2modify_only_ext(pb, be, &parent_addr,
dc8c34
-		                                        TOMBSTONE_INCLUDED, &txn);
dc8c34
+			parent = find_entry2modify_only_ext(pb, be, &parent_addr, TOMBSTONE_INCLUDED, &txn);
dc8c34
 		}
dc8c34
-		if (NULL != parent) {
dc8c34
+		if (parent) {
dc8c34
 			int isglue;
dc8c34
 			size_t haschildren = 0;
dc8c34
 			int op = PARENTUPDATE_DEL;
dc8c34
@@ -393,11 +416,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			} else if (delete_tombstone_entry) {
dc8c34
 				op |= PARENTUPDATE_DELETE_TOMBSTONE;
dc8c34
 			}
dc8c34
-			retval = parent_update_on_childchange(&parent_modify_c,
dc8c34
-			                                      op, &haschildren);
dc8c34
+			retval = parent_update_on_childchange(&parent_modify_c, op, &haschildren);
dc8c34
 			/* The modify context now contains info needed later */
dc8c34
 			if (0 != retval) {
dc8c34
 				ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+				slapi_sdn_done(&parentsdn);
dc8c34
 				goto error_return;
dc8c34
 			}
dc8c34
 			
dc8c34
@@ -426,10 +449,18 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 		 */
dc8c34
 		const char *childuniqueid= slapi_entry_get_uniqueid(e->ep_entry);
dc8c34
 		const char *parentuniqueid= NULL;
dc8c34
-		char *tombstone_dn = compute_entry_tombstone_dn(slapi_entry_get_dn(e->ep_entry),
dc8c34
-			childuniqueid);
dc8c34
+		char *edn = slapi_entry_get_dn(e->ep_entry);
dc8c34
+		char *tombstone_dn;
dc8c34
 		Slapi_Value *tomb_value;
dc8c34
 
dc8c34
+		if (slapi_is_special_rdn(edn, RDN_IS_TOMBSTONE)) {
dc8c34
+			LDAPDebug1Arg(LDAP_DEBUG_ANY, "Turning a tombstone into a tombstone! \"%s\"\n", edn);
dc8c34
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+			retval = -1;
dc8c34
+			goto error_return;
dc8c34
+		}
dc8c34
+		tombstone_dn = compute_entry_tombstone_dn(edn, childuniqueid);
dc8c34
+
dc8c34
 		slapi_sdn_set_ndn_byval(&nscpEntrySDN, slapi_sdn_get_ndn(slapi_entry_get_sdn(e->ep_entry)));
dc8c34
 
dc8c34
 		/* Copy the entry unique_id for URP conflict checking */
dc8c34
@@ -471,6 +502,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 
dc8c34
 		if ( (original_tombstone = backentry_dup( tombstone )) == NULL ) {
dc8c34
 			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+			retval = -1;
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
 	}
dc8c34
@@ -505,6 +537,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 				if (tombstone_in_cache) {
dc8c34
 					CACHE_REMOVE(&inst->inst_cache, tombstone);
dc8c34
 					CACHE_RETURN(&inst->inst_cache, &tombstone);
dc8c34
+					tombstone = NULL;
dc8c34
 					tombstone_in_cache = 0; 
dc8c34
 				} else {
dc8c34
 					backentry_free(&tombstone);
dc8c34
@@ -515,13 +548,6 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 					goto error_return;
dc8c34
 				}
dc8c34
 			}
dc8c34
-
dc8c34
-			/* reset original entry in cache */
dc8c34
-			if (!e_in_cache) {
dc8c34
-				CACHE_ADD(&inst->inst_cache, e, NULL);
dc8c34
-				e_in_cache = 1;
dc8c34
-			}
dc8c34
-
dc8c34
 			if (ruv_c_init) {
dc8c34
 				/* reset the ruv txn stuff */
dc8c34
 				modify_term(&ruv_c, be);
dc8c34
@@ -615,41 +641,85 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			 * tentatively for now, then cache_add again when the original
dc8c34
 			 * entry is removed from the cache.
dc8c34
 			 */
dc8c34
-			if (cache_add_tentative( &inst->inst_cache, tombstone, NULL) == 0) {
dc8c34
+			retval = cache_add_tentative(&inst->inst_cache, tombstone, NULL);
dc8c34
+			if (0 == retval) {
dc8c34
 				tombstone_in_cache = 1;
dc8c34
-			} else if (!(tombstone->ep_state & ENTRY_STATE_NOTINCACHE)) {
dc8c34
-			    LDAPDebug1Arg(LDAP_DEBUG_CACHE,
dc8c34
-			                  "id2entry_add tombstone (%s) is in cache\n",
dc8c34
-			                  slapi_entry_get_dn(tombstone->ep_entry));
dc8c34
-			    tombstone_in_cache = 1;
dc8c34
+			} else {
dc8c34
+				LDAPDebug2Args(LDAP_DEBUG_ANY,
dc8c34
+				               "tombstone entry %s failed to add to the cache: %d\n",
dc8c34
+				               slapi_entry_get_dn(tombstone->ep_entry), retval);
dc8c34
+				tombstone_in_cache = 0;
dc8c34
+				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
dc8c34
+				DEL_SET_ERROR(ldap_result_code, 
dc8c34
+							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+				goto error_return;
dc8c34
 			}
dc8c34
 			retval = id2entry_add( be, tombstone, &txn );
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 1 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM, "delete 1 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
dc8c34
 				/* Abort and re-try */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
-			if (0 != retval) {
dc8c34
+			if (retval) {
dc8c34
 				LDAPDebug( LDAP_DEBUG_ANY, "id2entry_add failed, err=%d %s\n",
dc8c34
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
+				           retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
dc8c34
-				DEL_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+				DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 				goto error_return;
dc8c34
 			}
dc8c34
-			if (cache_replace( &inst->inst_cache, e, tombstone ) != 0 ) {
dc8c34
-				LDAPDebug0Args( LDAP_DEBUG_BACKLDBM, "ldbm_back_delete cache_replace failed\n");
dc8c34
-				DEL_SET_ERROR(ldap_result_code, 
dc8c34
-							  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
-				retval= -1;
dc8c34
-				goto error_return;
dc8c34
+			if (tombstone_in_cache) {
dc8c34
+				retval = cache_replace(&inst->inst_cache, e, tombstone);
dc8c34
+				if (retval) {
dc8c34
+					LDAPDebug(LDAP_DEBUG_CACHE, "ldbm_back_delete: cache_replace failed (%d): %s --> %s\n",
dc8c34
+					          retval, slapi_entry_get_dn(e->ep_entry), slapi_entry_get_dn(tombstone->ep_entry));
dc8c34
+					retval= -1;
dc8c34
+					DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+					goto error_return;
dc8c34
+				}
dc8c34
 			} else {
dc8c34
-				e_in_cache = 0; /* e un-cached */
dc8c34
+				struct backentry *imposter = NULL;
dc8c34
+				retval = CACHE_ADD(&inst->inst_cache, tombstone, &imposter);
dc8c34
+				if (retval > 0) {
dc8c34
+					if (imposter) {
dc8c34
+						/* 
dc8c34
+						 * The same tombstone entry (different Slapi_Entry) is already
dc8c34
+						 * generated and set to cache.  Back off. 
dc8c34
+						 */
dc8c34
+						CACHE_RETURN(&inst->inst_cache, &imposter);
dc8c34
+						LDAPDebug1Arg(LDAP_DEBUG_CACHE, 
dc8c34
+						              "ldbm_delete: cache add: same DN tombstone in cache: %s\n",
dc8c34
+						              slapi_entry_get_dn(tombstone->ep_entry));
dc8c34
+					} else {
dc8c34
+						/* 
dc8c34
+						 * The same tombstone entry (same Slapi_Entry) is being created.
dc8c34
+						 * Something is wrong.  We should clean it up from the cache,
dc8c34
+						 * and back off.
dc8c34
+						 */
dc8c34
+						tombstone_in_cache = 1;
dc8c34
+						LDAPDebug1Arg(LDAP_DEBUG_CACHE, 
dc8c34
+						              "ldbm_delete: cache add: same tombstone in cache: %s\n",
dc8c34
+						              slapi_entry_get_dn(tombstone->ep_entry));
dc8c34
+					}
dc8c34
+					retval= -1;
dc8c34
+					DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+					goto error_return;
dc8c34
+				} else if (retval < 0) {
dc8c34
+					LDAPDebug1Arg(LDAP_DEBUG_CACHE, 
dc8c34
+					              "ldbm_delete: cache add: Add %s failed.\n",
dc8c34
+					              slapi_entry_get_dn(tombstone->ep_entry));
dc8c34
+					/* Complete add error */
dc8c34
+					retval= -1;
dc8c34
+					DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+					goto error_return;
dc8c34
+				}
dc8c34
 			}
dc8c34
-			/* tombstone was already added to the cache via cache_add_tentative (to reserve its spot in the cache)
dc8c34
-			   and/or id2entry_add - so it already had one refcount - cache_replace adds another refcount -
dc8c34
-			   drop the extra ref added by cache_replace */
dc8c34
-			CACHE_RETURN( &inst->inst_cache, &tombstone );
dc8c34
+			if (tombstone_in_cache) {
dc8c34
+				/* tombstone was already added to the cache via cache_add_tentative (to reserve its spot in the cache)
dc8c34
+				   and/or id2entry_add - so it already had one refcount - cache_replace adds another refcount -
dc8c34
+				   drop the extra ref added by cache_replace */
dc8c34
+				CACHE_RETURN( &inst->inst_cache, &tombstone );
dc8c34
+			}
dc8c34
+			tombstone_in_cache = 1;
dc8c34
 		}
dc8c34
 		else
dc8c34
 		{
dc8c34
@@ -657,12 +727,12 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			retval = id2entry_delete( be, e, &txn );
dc8c34
 			if (DB_LOCK_DEADLOCK == retval)
dc8c34
 			{
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 2 DEADLOCK\n", 0, 0, 0 );
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM, "delete 2 DEADLOCK\n", 0, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (retval  != 0 ) {
dc8c34
-			  	if (retval == DB_RUNRECOVERY || 
dc8c34
+				if (retval == DB_RUNRECOVERY || 
dc8c34
 				    LDBM_OS_ERR_IS_DISKFULL(retval)) {
dc8c34
 				    disk_full = 1;
dc8c34
 				}
dc8c34
@@ -680,12 +750,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 		retval = index_addordel_entry( be, e, addordel_flags, &txn );
dc8c34
 		if (DB_LOCK_DEADLOCK == retval)
dc8c34
 		{
dc8c34
-			LDAPDebug( LDAP_DEBUG_ARGS, "delete 1 DEADLOCK\n", 0, 0, 0 );
dc8c34
+			LDAPDebug( LDAP_DEBUG_BACKLDBM, "delete 1 DEADLOCK\n", 0, 0, 0 );
dc8c34
 			/* Retry txn */
dc8c34
 			continue;
dc8c34
 		}
dc8c34
-		if (retval != 0) {
dc8c34
-			LDAPDebug( LDAP_DEBUG_TRACE, "index_del_entry failed\n", 0, 0, 0 );
dc8c34
+		if (retval) {
dc8c34
+			LDAPDebug(LDAP_DEBUG_ANY, "index_del_entry(%s, 0x%x) failed (%d)\n", 
dc8c34
+			          slapi_entry_get_dn(e->ep_entry), addordel_flags, retval);
dc8c34
 			DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 			goto error_return;
dc8c34
 		}
dc8c34
@@ -700,14 +771,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							SLAPI_ATTR_VALUE_TOMBSTONE,
dc8c34
 							tombstone->ep_id,BE_INDEX_ADD, &txn);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 							"delete (adding %s) DB_LOCK_DEADLOCK\n",
dc8c34
 							SLAPI_ATTR_VALUE_TOMBSTONE, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
 							"delete (adding %s) failed, err=%d %s\n",
dc8c34
 							SLAPI_ATTR_VALUE_TOMBSTONE, retval,
dc8c34
 							(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -720,14 +791,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							slapi_entry_get_uniqueid(tombstone->ep_entry),
dc8c34
 							tombstone->ep_id,BE_INDEX_ADD,&txn);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 							"delete (adding %s) DB_LOCK_DEADLOCK\n",
dc8c34
 							SLAPI_ATTR_UNIQUEID, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
 							"delete (adding %s) failed, err=%d %s\n",
dc8c34
 							SLAPI_ATTR_UNIQUEID, retval,
dc8c34
 							(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -740,14 +811,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							slapi_sdn_get_ndn(&nscpEntrySDN),
dc8c34
 							tombstone->ep_id, BE_INDEX_ADD, &txn);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 							"delete (adding %s) DB_LOCK_DEADLOCK\n",
dc8c34
 							SLAPI_ATTR_NSCP_ENTRYDN, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE, 
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY, 
dc8c34
 							"delete (adding %s) failed, err=%d %s\n",
dc8c34
 							SLAPI_ATTR_NSCP_ENTRYDN, retval,
dc8c34
 							(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -764,14 +835,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							entryusn_str, tombstone->ep_id, BE_INDEX_ADD, &txn);
dc8c34
 				slapi_ch_free_string(&entryusn_str);
dc8c34
 				if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-					LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+					LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 								"delete (adding %s) DB_LOCK_DEADLOCK\n",
dc8c34
 								SLAPI_ATTR_ENTRYUSN, 0, 0 );
dc8c34
 					/* Retry txn */
dc8c34
 					continue;
dc8c34
 				}
dc8c34
 				if (0 != retval) {
dc8c34
-					LDAPDebug( LDAP_DEBUG_TRACE, 
dc8c34
+					LDAPDebug( LDAP_DEBUG_ANY, 
dc8c34
 								"delete (adding %s) failed, err=%d %s\n",
dc8c34
 								SLAPI_ATTR_ENTRYUSN, retval,
dc8c34
 								(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -795,13 +866,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 					                                  svals, NULL, e->ep_id, 
dc8c34
 					                                  BE_INDEX_ADD, &txn);
dc8c34
 					if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-						LDAPDebug0Args( LDAP_DEBUG_ARGS,
dc8c34
+						LDAPDebug0Args( LDAP_DEBUG_BACKLDBM,
dc8c34
 										"delete (updating " LDBM_PARENTID_STR ") DB_LOCK_DEADLOCK\n");
dc8c34
 						/* Retry txn */
dc8c34
 						continue;
dc8c34
 					}
dc8c34
 					if ( retval ) {
dc8c34
-						LDAPDebug( LDAP_DEBUG_TRACE, 
dc8c34
+						LDAPDebug( LDAP_DEBUG_ANY, 
dc8c34
 								"delete (deleting %s) failed, err=%d %s\n",
dc8c34
 								LDBM_PARENTID_STR, retval,
dc8c34
 								(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -811,15 +882,16 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 						goto error_return;
dc8c34
 					}
dc8c34
 				}
dc8c34
+#if 0 /* The entryrdn element is already deleted in the index_addordel_entry */
dc8c34
 				retval = entryrdn_index_entry(be, e, BE_INDEX_DEL, &txn);
dc8c34
 				if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-					LDAPDebug0Args( LDAP_DEBUG_ARGS,
dc8c34
+					LDAPDebug0Args( LDAP_DEBUG_BACKLDBM,
dc8c34
 								"delete (deleting entryrdn) DB_LOCK_DEADLOCK\n");
dc8c34
 					/* Retry txn */
dc8c34
 					continue;
dc8c34
 				}
dc8c34
-				if (0 != retval) {
dc8c34
-					LDAPDebug2Args( LDAP_DEBUG_TRACE, 
dc8c34
+				if (retval) {
dc8c34
+					LDAPDebug2Args( LDAP_DEBUG_ANY, 
dc8c34
 								"delete (deleting entryrdn) failed, err=%d %s\n",
dc8c34
 								retval,
dc8c34
 								(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -828,21 +900,22 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 								  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 					goto error_return;
dc8c34
 				}
dc8c34
+#endif
dc8c34
 				retval = entryrdn_index_entry(be, tombstone, BE_INDEX_ADD, &txn);
dc8c34
 				if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-					LDAPDebug0Args( LDAP_DEBUG_ARGS,
dc8c34
+					LDAPDebug0Args( LDAP_DEBUG_BACKLDBM,
dc8c34
 								"adding (adding tombstone entryrdn) DB_LOCK_DEADLOCK\n");
dc8c34
 					/* Retry txn */
dc8c34
 					continue;
dc8c34
 				}
dc8c34
-				if (0 != retval) {
dc8c34
-					LDAPDebug2Args( LDAP_DEBUG_TRACE, 
dc8c34
-								"adding (adding tombstone entryrdn) failed, err=%d %s\n",
dc8c34
-								retval,
dc8c34
-								(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
+				if (retval) {
dc8c34
+					LDAPDebug(LDAP_DEBUG_ANY, 
dc8c34
+					          "adding (adding tombstone entryrdn %s) failed, err=%d %s\n",
dc8c34
+					          slapi_entry_get_dn(tombstone->ep_entry),
dc8c34
+					          retval, (msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
+ 					if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
dc8c34
 					if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
dc8c34
-					DEL_SET_ERROR(ldap_result_code, 
dc8c34
-								  LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+					DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 					goto error_return;
dc8c34
 				}
dc8c34
 			}
dc8c34
@@ -859,14 +932,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							SLAPI_ATTR_VALUE_TOMBSTONE, e->ep_id,
dc8c34
 							BE_INDEX_DEL, &txn);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 							"delete (deleting %s) DB_LOCK_DEADLOCK\n",
dc8c34
 							SLAPI_ATTR_VALUE_TOMBSTONE, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
 							"delete (deleting %s) failed, err=%d %s\n",
dc8c34
 							SLAPI_ATTR_VALUE_TOMBSTONE, retval,
dc8c34
 							(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -879,14 +952,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							slapi_entry_get_uniqueid(e->ep_entry),
dc8c34
 							e->ep_id, BE_INDEX_DEL, &txn);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 							"delete (deleting %s) DB_LOCK_DEADLOCK\n",
dc8c34
 							SLAPI_ATTR_UNIQUEID, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
 							"delete (deleting %s) failed, err=%d %s\n",
dc8c34
 							SLAPI_ATTR_UNIQUEID, retval,
dc8c34
 							(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -903,14 +976,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 								nscpedn, e->ep_id, BE_INDEX_DEL, &txn);
dc8c34
 				slapi_ch_free((void **)&nscpedn);
dc8c34
 				if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-					LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+					LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 								"delete (deleting %s) DB_LOCK_DEADLOCK\n",
dc8c34
 								SLAPI_ATTR_NSCP_ENTRYDN, 0, 0 );
dc8c34
 					/* Retry txn */
dc8c34
 					continue;
dc8c34
 				}
dc8c34
 				if (0 != retval) {
dc8c34
-					LDAPDebug( LDAP_DEBUG_TRACE,
dc8c34
+					LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
 								"delete (deleting %s) failed, err=%d %s\n",
dc8c34
 								SLAPI_ATTR_NSCP_ENTRYDN, retval,
dc8c34
 								(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -929,14 +1002,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 							BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
dc8c34
 				slapi_ch_free_string(&entryusn_str);
dc8c34
 				if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-					LDAPDebug( LDAP_DEBUG_ARGS,
dc8c34
+					LDAPDebug( LDAP_DEBUG_BACKLDBM,
dc8c34
 								"delete (deleting %s) DB_LOCK_DEADLOCK\n",
dc8c34
 								SLAPI_ATTR_ENTRYUSN, 0, 0 );
dc8c34
 					/* Retry txn */
dc8c34
 					continue;
dc8c34
 				}
dc8c34
 				if (0 != retval) {
dc8c34
-					LDAPDebug( LDAP_DEBUG_TRACE, 
dc8c34
+					LDAPDebug( LDAP_DEBUG_ANY, 
dc8c34
 								"delete (deleting %s) failed, err=%d %s\n",
dc8c34
 								SLAPI_ATTR_ENTRYUSN, retval,
dc8c34
 								(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -950,13 +1023,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			{
dc8c34
 				retval = entryrdn_index_entry(be, e, BE_INDEX_DEL, &txn);
dc8c34
 				if (DB_LOCK_DEADLOCK == retval) {
dc8c34
-					LDAPDebug0Args( LDAP_DEBUG_ARGS,
dc8c34
+					LDAPDebug0Args( LDAP_DEBUG_BACKLDBM,
dc8c34
 							"delete (deleting entryrdn) DB_LOCK_DEADLOCK\n");
dc8c34
 					/* Retry txn */
dc8c34
 					continue;
dc8c34
 				}
dc8c34
 				if (0 != retval) {
dc8c34
-					LDAPDebug2Args( LDAP_DEBUG_TRACE, 
dc8c34
+					LDAPDebug2Args( LDAP_DEBUG_ANY, 
dc8c34
 							"delete (deleting entryrdn) failed, err=%d %s\n",
dc8c34
 							retval,
dc8c34
 							(msg = dblayer_strerror( retval )) ? msg : "" );
dc8c34
@@ -973,12 +1046,12 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			retval = modify_update_all(be,pb,&parent_modify_c,&txn);
dc8c34
 			if (DB_LOCK_DEADLOCK == retval)
dc8c34
 			{
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS, "del 4 DEADLOCK\n", 0, 0, 0 );
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM, "del 4 DEADLOCK\n", 0, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
 			if (0 != retval) {
dc8c34
-				LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY, "delete 3 BAD, err=%d %s\n",
dc8c34
 					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
dc8c34
 				DEL_SET_ERROR(ldap_result_code, 
dc8c34
@@ -996,7 +1069,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 
dc8c34
 			if (DB_LOCK_DEADLOCK == retval)
dc8c34
 			{
dc8c34
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete DEADLOCK vlv_update_index\n", 0, 0, 0 );
dc8c34
+				LDAPDebug( LDAP_DEBUG_BACKLDBM, "delete DEADLOCK vlv_update_index\n", 0, 0, 0 );
dc8c34
 				/* Retry txn */
dc8c34
 				continue;
dc8c34
 			}
dc8c34
@@ -1087,14 +1160,24 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 
dc8c34
 	/* delete from cache and clean up */
dc8c34
 	if (e) {
dc8c34
+		if (entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+			/* since the op was successful, delete the tombstone dn from the dn cache */
dc8c34
+			struct backdn *bdn = dncache_find_id(&inst->inst_dncache, e->ep_id);
dc8c34
+			if (bdn) { /* in the dncache, remove it. */
dc8c34
+				CACHE_REMOVE(&inst->inst_dncache, bdn);
dc8c34
+				CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+			}
dc8c34
+		}
dc8c34
 		if (e_in_cache) {
dc8c34
 			CACHE_REMOVE(&inst->inst_cache, e);
dc8c34
+			cache_unlock_entry(&inst->inst_cache, e);
dc8c34
+			CACHE_RETURN(&inst->inst_cache, &e);
dc8c34
+		} else {
dc8c34
+			cache_unlock_entry(&inst->inst_cache, e);
dc8c34
 		}
dc8c34
-		cache_unlock_entry(&inst->inst_cache, e);
dc8c34
-		CACHE_RETURN(&inst->inst_cache, &e);
dc8c34
 		e = NULL;
dc8c34
 	}
dc8c34
-	
dc8c34
+
dc8c34
 	if (ruv_c_init) {
dc8c34
 		if (modify_switch_entries(&ruv_c, be) != 0 ) {
dc8c34
 			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
@@ -1115,16 +1198,37 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 	goto common_return;
dc8c34
 
dc8c34
 error_return:
dc8c34
-	if (tombstone_in_cache)
dc8c34
-	{
dc8c34
-		CACHE_REMOVE( &inst->inst_cache, tombstone );
dc8c34
-		CACHE_RETURN( &inst->inst_cache, &tombstone );
dc8c34
-		tombstone = NULL;
dc8c34
-		tombstone_in_cache = 0;
dc8c34
+	if (tombstone) {
dc8c34
+		if (entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+			/* since the op was successful, add the addingentry's dn to the dn cache */
dc8c34
+			struct backdn *bdn = dncache_find_id(&inst->inst_dncache, tombstone->ep_id);
dc8c34
+			if (bdn) { /* already in the dncache. Delete it. */
dc8c34
+				CACHE_REMOVE(&inst->inst_dncache, bdn);
dc8c34
+				CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+			} 
dc8c34
+		}
dc8c34
+		if (tombstone_in_cache) { /* successfully replaced */
dc8c34
+			CACHE_REMOVE( &inst->inst_cache, tombstone );
dc8c34
+			CACHE_RETURN( &inst->inst_cache, &tombstone );
dc8c34
+			tombstone = NULL;
dc8c34
+			tombstone_in_cache = 0;
dc8c34
+		} else {
dc8c34
+			backentry_free( &tombstone );
dc8c34
+		}
dc8c34
 	}
dc8c34
-	else
dc8c34
-	{
dc8c34
-		backentry_free( &tombstone );
dc8c34
+
dc8c34
+	/* Need to return to cache after post op plugins are called */
dc8c34
+	if (e) {
dc8c34
+		if (e_in_cache) {
dc8c34
+			if (remove_e_from_cache) {
dc8c34
+				/* The entry is already transformed to a tombstone. */
dc8c34
+				CACHE_REMOVE( &inst->inst_cache, e );
dc8c34
+			}
dc8c34
+			cache_unlock_entry( &inst->inst_cache, e );
dc8c34
+			CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
+		} else {
dc8c34
+			cache_unlock_entry( &inst->inst_cache, e );
dc8c34
+		}
dc8c34
 	}
dc8c34
 
dc8c34
 	if (retval == DB_RUNRECOVERY) {
dc8c34
@@ -1184,15 +1288,32 @@ common_return:
dc8c34
 		   for the post op plugins */
dc8c34
 		slapi_pblock_set( pb, SLAPI_DELETE_BEPREOP_ENTRY, orig_entry );
dc8c34
 	}
dc8c34
-	if (tombstone_in_cache)
dc8c34
-	{
dc8c34
-		CACHE_RETURN( &inst->inst_cache, &tombstone );
dc8c34
-		tombstone = NULL;
dc8c34
-		tombstone_in_cache = 0;
dc8c34
-	}
dc8c34
-	else
dc8c34
-	{
dc8c34
-		backentry_free( &tombstone );
dc8c34
+	if (tombstone) {
dc8c34
+		if ((0 == retval) && entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+			/* since the op was successful, add the addingentry's dn to the dn cache */
dc8c34
+			struct backdn *bdn = dncache_find_id(&inst->inst_dncache, tombstone->ep_id);
dc8c34
+			if (bdn) { /* already in the dncache */
dc8c34
+				CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+			} else { /* not in the dncache yet */
dc8c34
+				Slapi_DN *tombstonesdn = slapi_sdn_dup(slapi_entry_get_sdn(tombstone->ep_entry));
dc8c34
+				if (tombstonesdn) {
dc8c34
+					bdn = backdn_init(tombstonesdn, tombstone->ep_id, 0);
dc8c34
+					if (bdn) {
dc8c34
+						CACHE_ADD( &inst->inst_dncache, bdn, NULL );
dc8c34
+						slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
dc8c34
+						                "set %s to dn cache\n", slapi_sdn_get_dn(tombstonesdn));
dc8c34
+						CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+					}
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
+		if (tombstone_in_cache) { /* successfully replaced */
dc8c34
+			CACHE_RETURN( &inst->inst_cache, &tombstone );
dc8c34
+			tombstone = NULL;
dc8c34
+			tombstone_in_cache = 0;
dc8c34
+		} else {
dc8c34
+			backentry_free( &tombstone );
dc8c34
+		}
dc8c34
 	}
dc8c34
 	
dc8c34
 	/* result code could be used in the bepost plugin functions. */
dc8c34
@@ -1205,14 +1326,6 @@ common_return:
dc8c34
 		plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_DELETE_FN);
dc8c34
 	}
dc8c34
 
dc8c34
-	/* Need to return to cache after post op plugins are called */
dc8c34
-	if (retval) { /* error case */
dc8c34
-		if (e) {
dc8c34
-			cache_unlock_entry( &inst->inst_cache, e );
dc8c34
-			CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
-		}
dc8c34
-	}
dc8c34
-	
dc8c34
 	if (ruv_c_init) {
dc8c34
 		modify_term(&ruv_c, be);
dc8c34
 	}
dc8c34
@@ -1222,7 +1335,7 @@ diskfull_return:
dc8c34
 	{
dc8c34
 		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
dc8c34
 	}
dc8c34
-	modify_term(&parent_modify_c,be);
dc8c34
+	modify_term(&parent_modify_c, be);
dc8c34
 	if(dblock_acquired)
dc8c34
 	{
dc8c34
 		dblayer_unlock_backend(be);
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
dc8c34
index 887f74b..6426fb7 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
dc8c34
@@ -387,7 +387,7 @@ entryrdn_index_read_ext(backend *be,
dc8c34
 
dc8c34
     rc = slapi_rdn_init_all_sdn(&srdn, sdn);
dc8c34
     if (rc < 0) {
dc8c34
-        slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
dc8c34
+        slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
dc8c34
                         "entryrdn_index_read: Param error: Failed to convert "
dc8c34
                         "%s to Slapi_RDN\n", slapi_sdn_get_dn(sdn));
dc8c34
         rc = LDAP_INVALID_DN_SYNTAX;
dc8c34
@@ -501,7 +501,8 @@ entryrdn_rename_subtree(backend *be,
dc8c34
                         Slapi_RDN *newsrdn,        /* new rdn */
dc8c34
                         const Slapi_DN *newsupsdn, /* new superior dn */
dc8c34
                         ID id,
dc8c34
-                        back_txn *txn)
dc8c34
+                        back_txn *txn,
dc8c34
+                        int flags)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
     struct attrinfo *ai = NULL;
dc8c34
@@ -543,7 +544,7 @@ entryrdn_rename_subtree(backend *be,
dc8c34
         goto bail;
dc8c34
     }
dc8c34
 
dc8c34
-    rc = slapi_rdn_init_all_sdn(&oldsrdn, oldsdn);
dc8c34
+    rc = slapi_rdn_init_all_sdn_ext(&oldsrdn, oldsdn, flags);
dc8c34
     if (rc < 0) {
dc8c34
         slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
dc8c34
                         "entryrdn_rename_subtree: Failed to convert olddn "
dc8c34
@@ -968,7 +969,8 @@ entryrdn_get_subordinates(backend *be,
dc8c34
                           const Slapi_DN *sdn,
dc8c34
                           ID id,
dc8c34
                           IDList **subordinates,
dc8c34
-                          back_txn *txn)
dc8c34
+                          back_txn *txn,
dc8c34
+                          int flags)
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
     struct attrinfo *ai = NULL;
dc8c34
@@ -1000,7 +1002,7 @@ entryrdn_get_subordinates(backend *be,
dc8c34
         goto bail;
dc8c34
     }
dc8c34
 
dc8c34
-    rc = slapi_rdn_init_all_sdn(&srdn, sdn);
dc8c34
+    rc = slapi_rdn_init_all_sdn_ext(&srdn, sdn, flags);
dc8c34
     if (rc) {
dc8c34
         if (rc < 0) {
dc8c34
             slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
index be47fcc..f7ebac1 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
@@ -116,8 +116,14 @@ int modify_switch_entries(modify_context *mc,backend *be)
dc8c34
 	ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
dc8c34
 	int ret = 0;
dc8c34
 	if (mc->old_entry!=NULL && mc->new_entry!=NULL) {
dc8c34
-	    ret = cache_replace(&(inst->inst_cache), mc->old_entry, mc->new_entry);
dc8c34
-            if (ret == 0) mc->new_entry_in_cache = 1;
dc8c34
+		ret = cache_replace(&(inst->inst_cache), mc->old_entry, mc->new_entry);
dc8c34
+		if (ret == 0) {
dc8c34
+			mc->new_entry_in_cache = 1;
dc8c34
+		} else {
dc8c34
+			LDAPDebug(LDAP_DEBUG_CACHE, "modify_switch_entries: replacing %s with %s failed (%d)\n",
dc8c34
+			          slapi_entry_get_dn(mc->old_entry->ep_entry), 
dc8c34
+			          slapi_entry_get_dn(mc->new_entry->ep_entry), ret);
dc8c34
+		}
dc8c34
 	}
dc8c34
 	return ret;
dc8c34
 }
dc8c34
@@ -154,6 +160,10 @@ modify_unswitch_entries(modify_context *mc,backend *be)
dc8c34
 			CACHE_RETURN( &(inst->inst_cache), &(mc->old_entry) );
dc8c34
 			mc->new_entry_in_cache = 1;
dc8c34
 			mc->old_entry = NULL;
dc8c34
+		} else {
dc8c34
+			LDAPDebug(LDAP_DEBUG_CACHE, "modify_unswitch_entries: replacing %s with %s failed (%d)\n",
dc8c34
+			          slapi_entry_get_dn(mc->old_entry->ep_entry), 
dc8c34
+			          slapi_entry_get_dn(mc->new_entry->ep_entry), ret);
dc8c34
 		}
dc8c34
 	}
dc8c34
 
dc8c34
@@ -722,6 +732,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
dc8c34
 		MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
 		goto error_return;
dc8c34
 	}
dc8c34
+	/* e uncached */
dc8c34
+	/* we must return both e (which has been deleted) and new entry ec */
dc8c34
+	/* cache_replace removes e from the caches */
dc8c34
+	cache_unlock_entry( &inst->inst_cache, e );
dc8c34
+	CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
+
dc8c34
 	/* lock new entry in cache to prevent usage until we are complete */
dc8c34
 	cache_lock_entry( &inst->inst_cache, ec );
dc8c34
 	ec_in_cache = 1;
dc8c34
@@ -732,10 +748,6 @@ ldbm_back_modify( Slapi_PBlock *pb )
dc8c34
 	/* invalidate virtual cache */
dc8c34
 	ec->ep_entry->e_virtual_watermark = 0;
dc8c34
 
dc8c34
-	/* we must return both e (which has been deleted) and new entry ec */
dc8c34
-	/* cache_replace removes e from the caches */
dc8c34
-	cache_unlock_entry( &inst->inst_cache, e );
dc8c34
-	CACHE_RETURN( &inst->inst_cache, &e );
dc8c34
 	/* 
dc8c34
 	 * LP Fix of crash when the commit will fail:
dc8c34
 	 * If the commit fail, the common error path will
dc8c34
@@ -833,8 +845,10 @@ error_return:
dc8c34
 		CACHE_REMOVE( &inst->inst_cache, ec );
dc8c34
 		/* if ec was in cache, e was not - add back e */
dc8c34
 		if (e) {
dc8c34
-			CACHE_ADD( &inst->inst_cache, e, NULL );
dc8c34
-			cache_lock_entry( &inst->inst_cache, e );
dc8c34
+			if (CACHE_ADD( &inst->inst_cache, e, NULL )) {
dc8c34
+				LDAPDebug1Arg( LDAP_DEBUG_CACHE, "ldbm_modify: CACHE_ADD %s failed\n",
dc8c34
+							   slapi_entry_get_dn(e->ep_entry));
dc8c34
+			}
dc8c34
 		}
dc8c34
 	}
dc8c34
 
dc8c34
@@ -849,11 +863,12 @@ common_return:
dc8c34
 	else
dc8c34
 	{
dc8c34
 		backentry_free(&ec);
dc8c34
-	}
dc8c34
-	
dc8c34
-	if (e!=NULL) {
dc8c34
-		cache_unlock_entry( &inst->inst_cache, e);
dc8c34
-		CACHE_RETURN( &inst->inst_cache, &e);
dc8c34
+		/* if ec was not in cache, cache_replace was not done.
dc8c34
+		 * i.e., e was not unlocked. */
dc8c34
+		if (e) {
dc8c34
+			cache_unlock_entry( &inst->inst_cache, e);
dc8c34
+			CACHE_RETURN( &inst->inst_cache, &e);
dc8c34
+		}
dc8c34
 	}
dc8c34
 
dc8c34
 	/* result code could be used in the bepost plugin functions. */
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
index c539463..4e5ce45 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
@@ -45,10 +45,10 @@
dc8c34
 
dc8c34
 #include "back-ldbm.h"
dc8c34
 
dc8c34
-static const char *moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn);
dc8c34
+static const char *moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn, int is_tombstone);
dc8c34
 static void moddn_unlock_and_return_entry(backend *be,struct backentry **targetentry);
dc8c34
 static int moddn_newrdn_mods(Slapi_PBlock *pb, const char *olddn, struct backentry *ec, Slapi_Mods *smods_wsi, int is_repl_op);
dc8c34
-static IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backdn ***child_dns);
dc8c34
+static IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backdn ***child_dns, int is_resurect_operation);
dc8c34
 static int moddn_rename_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, IDList *children, Slapi_DN *dn_parentdn, Slapi_DN *dn_newsuperiordn, struct backentry *child_entries[]);
dc8c34
 static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3, int *e_in_cache, int *ec_in_cache);
dc8c34
 static void mods_remove_nsuniqueid(Slapi_Mods *smods);
dc8c34
@@ -111,6 +111,8 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     int dblock_acquired= 0;
dc8c34
     int is_replicated_operation= 0;
dc8c34
     int is_fixup_operation = 0;
dc8c34
+    int is_resurect_operation = 0;
dc8c34
+    int is_tombstone = 0;
dc8c34
     entry_address new_addr;
dc8c34
     entry_address *old_addr;
dc8c34
     entry_address oldparent_addr;
dc8c34
@@ -136,6 +138,8 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation );
dc8c34
     is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV);
dc8c34
     is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP);
dc8c34
+    is_resurect_operation = operation_is_flag_set(operation,OP_FLAG_RESURECT_ENTRY);
dc8c34
+    is_tombstone = operation_is_flag_set(operation,OP_FLAG_TOMBSTONE_ENTRY); /* tombstone_to_glue on parent entry*/
dc8c34
 
dc8c34
     if (NULL == sdn) {
dc8c34
         slapi_send_ldap_result( pb, LDAP_INVALID_DN_SYNTAX, NULL,
dc8c34
@@ -168,7 +172,13 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &dn_newsuperiordn );
dc8c34
         slapi_sdn_init_normdn_byref(&dn_newrdn, newrdn);
dc8c34
         /* slapi_sdn_init_normdn_byref(&dn_newsuperiordn, newsuperiordn); */
dc8c34
-        slapi_sdn_get_parent(sdn, &dn_parentdn);
dc8c34
+        if (is_resurect_operation) {
dc8c34
+            /* no need to free this pdn. */
dc8c34
+            const char *pdn = slapi_dn_find_parent_ext(slapi_sdn_get_dn(sdn), is_resurect_operation);
dc8c34
+            slapi_sdn_set_dn_byval(&dn_parentdn, pdn);
dc8c34
+        } else {
dc8c34
+            slapi_sdn_get_parent(sdn, &dn_parentdn);
dc8c34
+        }
dc8c34
     }
dc8c34
     
dc8c34
     /* if old and new superior are equals, newsuperior should not be set
dc8c34
@@ -235,7 +245,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
              * it's passed to slapi_sdn_init_normdn_byref */
dc8c34
             slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
dc8c34
             slapi_sdn_init_normdn_byref(&dn_newrdn, newrdn);
dc8c34
-            newdn= moddn_get_newdn(pb,sdn, &dn_newrdn, dn_newsuperiordn);
dc8c34
+            newdn = moddn_get_newdn(pb, sdn, &dn_newrdn, dn_newsuperiordn, is_tombstone);
dc8c34
             slapi_sdn_set_dn_passin(&dn_newdn,newdn);
dc8c34
             new_addr.sdn = &dn_newdn;
dc8c34
             new_addr.udn = NULL;
dc8c34
@@ -353,11 +363,14 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     }
dc8c34
     e_in_cache = 1; /* e is in the cache and locked */
dc8c34
     if (slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE) ) {
dc8c34
-        ldap_result_code = LDAP_UNWILLING_TO_PERFORM;
dc8c34
-        ldap_result_message = "Operation not allowed on tombstone entry.";
dc8c34
-        slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_modrdn",
dc8c34
-               "Attempt to rename a tombstone entry %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry )));
dc8c34
-        goto error_return;
dc8c34
+        if (!is_resurect_operation) {
dc8c34
+            ldap_result_code = LDAP_UNWILLING_TO_PERFORM;
dc8c34
+            ldap_result_message = "Operation not allowed on tombstone entry.";
dc8c34
+            slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_modrdn",
dc8c34
+                            "Attempt to rename a tombstone entry %s\n",
dc8c34
+                            slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry )));
dc8c34
+            goto error_return;
dc8c34
+        }
dc8c34
     }
dc8c34
     /* Check that an entry with the same DN doesn't already exist. */
dc8c34
     {
dc8c34
@@ -375,7 +388,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
 
dc8c34
     /* Fetch and lock the parent of the entry that is moving */
dc8c34
     oldparent_addr.sdn = &dn_parentdn;
dc8c34
-    oldparent_addr.uniqueid = NULL;            
dc8c34
+    if (is_resurect_operation) {
dc8c34
+        oldparent_addr.uniqueid = operation->o_params.p.p_modrdn.modrdn_newsuperior_address.uniqueid;
dc8c34
+    } else {
dc8c34
+        oldparent_addr.uniqueid = NULL;            
dc8c34
+    }
dc8c34
     parententry = find_entry2modify_only( pb, be, &oldparent_addr, &txn );
dc8c34
     modify_init(&parent_modify_context,parententry);
dc8c34
 
dc8c34
@@ -383,7 +400,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
     if(slapi_sdn_get_ndn(dn_newsuperiordn) != NULL)
dc8c34
     {
dc8c34
         slapi_pblock_get (pb, SLAPI_MODRDN_NEWSUPERIOR_ADDRESS, &newsuperior_addr);
dc8c34
+        if (is_resurect_operation) {
dc8c34
+            newsuperior_addr->uniqueid = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
dc8c34
+        }
dc8c34
         newparententry = find_entry2modify_only( pb, be, newsuperior_addr, &txn );
dc8c34
+        slapi_ch_free_string(&newsuperior_addr->uniqueid);
dc8c34
         modify_init(&newparent_modify_context,newparententry);
dc8c34
     }
dc8c34
 
dc8c34
@@ -426,8 +447,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         }
dc8c34
         slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, dn_newsuperiordn );
dc8c34
     }
dc8c34
-    slapi_sdn_set_dn_passin(&dn_newdn,
dc8c34
-                        moddn_get_newdn(pb, sdn, &dn_newrdn, dn_newsuperiordn));
dc8c34
+    slapi_sdn_set_dn_passin(&dn_newdn, moddn_get_newdn(pb, sdn, &dn_newrdn, dn_newsuperiordn, is_tombstone));
dc8c34
 
dc8c34
     /* Check that we're allowed to add an entry below the new superior */
dc8c34
     if ( newparententry == NULL )
dc8c34
@@ -528,6 +548,57 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         slapi_rdn_done(&srdn);
dc8c34
     }
dc8c34
 
dc8c34
+    if(is_resurect_operation) {
dc8c34
+        slapi_log_error(SLAPI_LOG_REPL, "ldbm_back_modrdn",
dc8c34
+                        "Resurrecting an entry %s\n", slapi_entry_get_dn(ec->ep_entry));
dc8c34
+        slapi_entry_attr_delete(ec->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
dc8c34
+        slapi_entry_delete_string(ec->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
dc8c34
+        /* Now also remove the nscpEntryDN */
dc8c34
+        if (slapi_entry_attr_delete(ec->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN) != 0){
dc8c34
+            LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Couldn't remove %s\n", 
dc8c34
+                      slapi_entry_get_dn(ec->ep_entry), SLAPI_ATTR_NSCP_ENTRYDN, 0);
dc8c34
+        }
dc8c34
+        
dc8c34
+        /* Set the reason (this is only a reason why modrdn is needed for resurrection) */
dc8c34
+        slapi_entry_add_string(ec->ep_entry, "nsds5ReplConflict", "deletedEntryHasChildren");
dc8c34
+
dc8c34
+        /* Clear the Tombstone Flag in the entry */
dc8c34
+        slapi_entry_clear_flag(ec->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
dc8c34
+
dc8c34
+        /* make sure the objectclass
dc8c34
+           - does not contain any duplicate values
dc8c34
+           - has CSNs for the new values we added
dc8c34
+        */
dc8c34
+        {
dc8c34
+            Slapi_Attr *sa = NULL;
dc8c34
+            Slapi_Value sv;
dc8c34
+            const struct berval *svbv = NULL;
dc8c34
+
dc8c34
+            /* add the extensibleobject objectclass with csn if not present */
dc8c34
+            slapi_entry_attr_find(ec->ep_entry, SLAPI_ATTR_OBJECTCLASS, &sa);
dc8c34
+            slapi_value_init_string(&sv, "extensibleobject");
dc8c34
+            svbv = slapi_value_get_berval(&sv;;
dc8c34
+            if (slapi_attr_value_find(sa, svbv)) { /* not found, so add it */
dc8c34
+                if (opcsn) {
dc8c34
+                    value_update_csn(&sv, CSN_TYPE_VALUE_UPDATED, opcsn);
dc8c34
+                }
dc8c34
+                slapi_attr_add_value(sa, &sv;;
dc8c34
+            }
dc8c34
+            value_done(&sv;;
dc8c34
+            
dc8c34
+            /* add the glue objectclass with csn if not present */
dc8c34
+            slapi_value_init_string(&sv, "glue");
dc8c34
+            svbv = slapi_value_get_berval(&sv;;
dc8c34
+            if (slapi_attr_value_find(sa, svbv)) { /* not found, so add it */
dc8c34
+                if (opcsn) {
dc8c34
+                    value_update_csn(&sv, CSN_TYPE_VALUE_UPDATED, opcsn);
dc8c34
+                }
dc8c34
+                slapi_attr_add_value(sa, &sv;;
dc8c34
+            }
dc8c34
+            value_done(&sv;;
dc8c34
+        }
dc8c34
+    }
dc8c34
+
dc8c34
     /* create it in the cache - prevents others from creating it */
dc8c34
     if (( cache_add_tentative( &inst->inst_cache, ec, NULL ) != 0 ) ) {
dc8c34
         ec_in_cache = 0; /* not in cache */
dc8c34
@@ -537,6 +608,10 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
             /* somebody must've created it between dn2entry() and here */
dc8c34
             /* JCMREPL - Hmm... we can't permit this to happen...? */
dc8c34
             ldap_result_code= LDAP_ALREADY_EXISTS;
dc8c34
+            if (is_resurect_operation) {
dc8c34
+                slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_modrdn",
dc8c34
+                                "cache_add_tentative failed: %s\n", slapi_entry_get_dn(ec->ep_entry));
dc8c34
+            }
dc8c34
             goto error_return;
dc8c34
         }
dc8c34
         /* so if the old dn is the same as the new dn, the entry will not be cached
dc8c34
@@ -584,8 +659,8 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         }
dc8c34
     }
dc8c34
 
dc8c34
-       slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
dc8c34
-       slapi_mods_init_byref(&smods_operation_wsi,mods);
dc8c34
+    slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
dc8c34
+    slapi_mods_init_byref(&smods_operation_wsi,mods);
dc8c34
 
dc8c34
     /*
dc8c34
      * We are about to pass the last abandon test, so from now on we are
dc8c34
@@ -675,10 +750,8 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         /* 
dc8c34
          * Update the subordinate count of the parents to reflect the moved child.
dc8c34
          */
dc8c34
-        if ( parententry!=NULL )
dc8c34
-        {
dc8c34
-            retval = parent_update_on_childchange(&parent_modify_context,
dc8c34
-                                                  PARENTUPDATE_DEL, NULL);
dc8c34
+        if (parententry) {
dc8c34
+            retval = parent_update_on_childchange(&parent_modify_context, PARENTUPDATE_DEL, NULL);
dc8c34
             /* The parent modify context now contains info needed later */
dc8c34
             if (0 != retval)
dc8c34
             {
dc8c34
@@ -696,27 +769,64 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
             }
dc8c34
         }
dc8c34
     }
dc8c34
+    /* is_resurect_operation case, there's no new superior.  Just rename. */
dc8c34
+    if (is_resurect_operation && parententry) {
dc8c34
+        retval = parent_update_on_childchange(&parent_modify_context, PARENTUPDATE_RESURECT, NULL);
dc8c34
+        if (retval) {
dc8c34
+            LDAPDebug(LDAP_DEBUG_BACKLDBM, "parent_update_on_childchange parent %s of %s failed, rc=%d\n",
dc8c34
+                      slapi_entry_get_dn_const(parent_modify_context.old_entry->ep_entry),
dc8c34
+                      slapi_entry_get_dn_const(ec->ep_entry), retval);
dc8c34
+            goto error_return;
dc8c34
+        }
dc8c34
+    }
dc8c34
 
dc8c34
     /*
dc8c34
-     * If the entry has children then we're going to have to rename them all.
dc8c34
+     * If the entry has children including tombstones,
dc8c34
+     * then we're going to have to rename them all.
dc8c34
      */
dc8c34
-    if (slapi_entry_has_children( e->ep_entry ))
dc8c34
-    {
dc8c34
+    if (slapi_entry_has_children_ext(e->ep_entry, 1)) {
dc8c34
         /* JCM - This is where the subtree lock will appear */
dc8c34
         if (entryrdn_get_switch()) /* subtree-rename: on */
dc8c34
         {
dc8c34
+            if (is_resurect_operation) {
dc8c34
+#if defined(DEBUG)
dc8c34
+                /* Get the present value of the subcount attr, or 0 if not present */
dc8c34
+                Slapi_Attr *read_attr = NULL;
dc8c34
+                int sub_count = -1;
dc8c34
+                if (0 == slapi_entry_attr_find(parent_modify_context.old_entry->ep_entry,
dc8c34
+                                               "numsubordinates", &read_attr)) {
dc8c34
+                    /* decode the value */
dc8c34
+                    Slapi_Value *sval;
dc8c34
+                    slapi_attr_first_value(read_attr, &sval);
dc8c34
+                    if (sval) {
dc8c34
+                        const struct berval *bval = slapi_value_get_berval(sval);
dc8c34
+                        if(bval) {
dc8c34
+                            sub_count = atol(bval->bv_val);
dc8c34
+                        }
dc8c34
+                    }
dc8c34
+                }
dc8c34
+                LDAPDebug(LDAP_DEBUG_ANY, "parent_update_on_childchange parent %s of %s numsub=%d\n",
dc8c34
+                          slapi_entry_get_dn_const(parent_modify_context.old_entry->ep_entry),
dc8c34
+                          slapi_entry_get_dn_const(e->ep_entry), sub_count);
dc8c34
+#endif
dc8c34
+                slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
dc8c34
+                                "%s has children\n", slapi_entry_get_dn(e->ep_entry));
dc8c34
+            }
dc8c34
             children = moddn_get_children(&txn, pb, be, e, sdn,
dc8c34
-                                          &child_entries, &child_dns);
dc8c34
+                                          &child_entries, &child_dns, is_resurect_operation);
dc8c34
         }
dc8c34
         else
dc8c34
         {
dc8c34
             children = moddn_get_children(&txn, pb, be, e, sdn,
dc8c34
-                                          &child_entries, NULL);
dc8c34
+                                          &child_entries, NULL, 0);
dc8c34
         }
dc8c34
 
dc8c34
         /* JCM - Shouldn't we perform an access control check on all the children. */
dc8c34
         /* JCMREPL - But, the replication client has total rights over its subtree, so no access check needed. */
dc8c34
         /* JCM - A subtree move could break ACIs, static groups, and dynamic groups. */
dc8c34
+    } else if (is_resurect_operation) {
dc8c34
+        slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_modrdn",
dc8c34
+                        "%s has NO children\n", slapi_entry_get_dn(e->ep_entry));
dc8c34
     }
dc8c34
 
dc8c34
     /*
dc8c34
@@ -777,7 +887,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
             }
dc8c34
             /* make sure the original entry is back in the cache if it was removed */
dc8c34
             if (!e_in_cache) {
dc8c34
-                CACHE_ADD(&inst->inst_cache, e, NULL);
dc8c34
+                if (CACHE_ADD(&inst->inst_cache, e, NULL)) {
dc8c34
+                    LDAPDebug1Arg(LDAP_DEBUG_CACHE, 
dc8c34
+                                  "ldbm_back_modrdn: CACHE_ADD %s to cache failed\n",
dc8c34
+                                  slapi_entry_get_dn_const(e->ep_entry));
dc8c34
+                }
dc8c34
                 e_in_cache = 1;
dc8c34
             }
dc8c34
             slapi_pblock_get( pb, SLAPI_MODRDN_EXISTING_ENTRY, &ent );
dc8c34
@@ -820,11 +934,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
                 goto error_return;
dc8c34
             }
dc8c34
 
dc8c34
-	    if (ruv_c_init) {
dc8c34
-		/* reset the ruv txn stuff */
dc8c34
-		modify_term(&ruv_c, be);
dc8c34
-		ruv_c_init = 0;
dc8c34
-	    }
dc8c34
+            if (ruv_c_init) {
dc8c34
+                /* reset the ruv txn stuff */
dc8c34
+                modify_term(&ruv_c, be);
dc8c34
+                ruv_c_init = 0;
dc8c34
+            }
dc8c34
             /* We're re-trying */
dc8c34
             LDAPDebug0Args(LDAP_DEBUG_BACKLDBM,
dc8c34
                            "Modrdn Retrying Transaction\n");
dc8c34
@@ -871,10 +985,10 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
             /* Retry txn */
dc8c34
             continue;
dc8c34
         }
dc8c34
-        if (retval != 0 )
dc8c34
+        if (retval)
dc8c34
         {
dc8c34
-            LDAPDebug( LDAP_DEBUG_TRACE, "modrdn_rename_entry_update_indexes failed, err=%d %s\n",
dc8c34
-                       retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
dc8c34
+            LDAPDebug(LDAP_DEBUG_ANY, "modrdn_rename_entry_update_indexes %s --> %s failed, err=%d\n",
dc8c34
+                      slapi_entry_get_dn(e->ep_entry), slapi_entry_get_dn(ec->ep_entry), retval);
dc8c34
             if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
dc8c34
             MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
             goto error_return;
dc8c34
@@ -994,14 +1108,17 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
             slapi_rdn_init_sdn(&newsrdn, (const Slapi_DN *)&dn_newdn);
dc8c34
             retval = entryrdn_rename_subtree(be, (const Slapi_DN *)sdn, &newsrdn,
dc8c34
                                              (const Slapi_DN *)dn_newsuperiordn,
dc8c34
-                                             e->ep_id, &txn);
dc8c34
+                                             e->ep_id, &txn, is_tombstone);
dc8c34
             slapi_rdn_done(&newsrdn);
dc8c34
             if (retval != 0) {
dc8c34
                 if (retval == DB_LOCK_DEADLOCK) continue;
dc8c34
                 if (retval == DB_RUNRECOVERY || LDBM_OS_ERR_IS_DISKFULL(retval))
dc8c34
                     disk_full = 1;
dc8c34
-                MOD_SET_ERROR(ldap_result_code, 
dc8c34
-                              LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+                MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
dc8c34
+                slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_modrdn",
dc8c34
+                                "entryrdn_rename_subtree failed (%d); dn: %s, newsrdn: %s, dn_newsuperiordn: %s\n",
dc8c34
+                                retval, slapi_sdn_get_dn(sdn), slapi_rdn_get_rdn(&newsrdn),
dc8c34
+                                slapi_sdn_get_dn(dn_newsuperiordn));
dc8c34
                 goto error_return;
dc8c34
             }
dc8c34
         }
dc8c34
@@ -1125,6 +1242,12 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
                  * "renamed" dn is generated based upon the moved subtree.
dc8c34
                  */
dc8c34
                 for (i = 0; child_entries[i] != NULL; i++) {
dc8c34
+                    if (is_resurect_operation) {
dc8c34
+                        slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_modrdn",
dc8c34
+                                        "Calling cache remove & return %s (refcnt: %d)\n", 
dc8c34
+                                        slapi_entry_get_dn(child_entries[i]->ep_entry),
dc8c34
+                                        child_entries[i]->ep_refcnt);
dc8c34
+                    }
dc8c34
                     CACHE_REMOVE( &inst->inst_cache, child_entries[i] );
dc8c34
                     cache_unlock_entry( &inst->inst_cache, child_entries[i] );
dc8c34
                     CACHE_RETURN( &inst->inst_cache, &child_entries[i] );
dc8c34
@@ -1168,12 +1291,6 @@ error_return:
dc8c34
         /* make sure caller doesn't attempt to free this */
dc8c34
         slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );
dc8c34
     }
dc8c34
-    if (e && entryrdn_get_switch())
dc8c34
-    {
dc8c34
-        struct backdn *bdn = dncache_find_id(&inst->inst_dncache, e->ep_id);
dc8c34
-        CACHE_REMOVE(&inst->inst_dncache, bdn);
dc8c34
-        CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
-    }
dc8c34
     if(children)
dc8c34
     {
dc8c34
         int i = 0;
dc8c34
@@ -1270,9 +1387,32 @@ common_return:
dc8c34
 
dc8c34
     /* Free up the resource we don't need any more */
dc8c34
     if (ec) {
dc8c34
+        if (is_resurect_operation) {
dc8c34
+            slapi_log_error(SLAPI_LOG_REPL, "ldbm_back_modrdn",
dc8c34
+                            "Resurrecting an entry %s: result: %d, %d\n", 
dc8c34
+                            slapi_entry_get_dn(ec->ep_entry), ldap_result_code, retval);
dc8c34
+        }
dc8c34
+        if ((0 == retval) && entryrdn_get_switch()) { /* subtree-rename: on */
dc8c34
+            /* since the op was successful, add the addingentry's dn to the dn cache */
dc8c34
+            struct backdn *bdn = dncache_find_id(&inst->inst_dncache, ec->ep_id);
dc8c34
+            if (bdn) { /* already in the dncache */
dc8c34
+                CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+            } else { /* not in the dncache yet */
dc8c34
+                Slapi_DN *ecsdn = slapi_sdn_dup(slapi_entry_get_sdn(ec->ep_entry));
dc8c34
+                if (ecsdn) {
dc8c34
+                    bdn = backdn_init(ecsdn, ec->ep_id, 0);
dc8c34
+                    if (bdn) {
dc8c34
+                        CACHE_ADD( &inst->inst_dncache, bdn, NULL );
dc8c34
+                        CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
+                        slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_modrdn",
dc8c34
+                                        "set %s to dn cache\n", slapi_sdn_get_dn(sdn));
dc8c34
+                    }
dc8c34
+                }
dc8c34
+            }
dc8c34
+        }
dc8c34
         /* remove the new entry from the cache if the op failed -
dc8c34
            otherwise, leave it in */
dc8c34
-        if (ec_in_cache && retval) {
dc8c34
+        if (ec_in_cache && ec && retval) {
dc8c34
             CACHE_REMOVE( &inst->inst_cache, ec );
dc8c34
         }
dc8c34
         if (ec_in_cache) {
dc8c34
@@ -1286,9 +1426,10 @@ common_return:
dc8c34
 
dc8c34
     /* put e back in the cache if the modrdn failed */
dc8c34
     if (e) {
dc8c34
-        if (!e_in_cache && retval) {
dc8c34
-            CACHE_ADD(&inst->inst_cache, e, NULL);
dc8c34
-            e_in_cache = 1;
dc8c34
+        if (entryrdn_get_switch() && (0 == retval)) {
dc8c34
+            struct backdn *bdn = dncache_find_id(&inst->inst_dncache, e->ep_id);
dc8c34
+            CACHE_REMOVE(&inst->inst_dncache, bdn);
dc8c34
+            CACHE_RETURN(&inst->inst_dncache, &bdn;;
dc8c34
         }
dc8c34
     }
dc8c34
 
dc8c34
@@ -1352,7 +1493,7 @@ common_return:
dc8c34
  * Work out what the new DN of the entry will be.
dc8c34
  */
dc8c34
 static const char *
dc8c34
-moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn)
dc8c34
+moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn, int is_tombstone)
dc8c34
 {
dc8c34
     char *newdn;
dc8c34
     const char *newrdn= slapi_sdn_get_dn(dn_newrdn);
dc8c34
@@ -1373,18 +1514,18 @@ moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi
dc8c34
     else
dc8c34
     {
dc8c34
         /* construct the new dn */
dc8c34
-        char *pdn;
dc8c34
-        const char *dn= slapi_sdn_get_dn(dn_olddn);
dc8c34
-        pdn = slapi_dn_beparent( pb, dn );
dc8c34
-        if ( pdn != NULL )
dc8c34
-        {
dc8c34
-            newdn= slapi_dn_plus_rdn(pdn, newrdn); /* JCM - Use Slapi_RDN */
dc8c34
-        }
dc8c34
-        else
dc8c34
-        {
dc8c34
-            newdn= slapi_ch_strdup(newrdn);
dc8c34
+        const char *dn = slapi_sdn_get_dn((const Slapi_DN *)dn_olddn);
dc8c34
+        if (slapi_dn_isbesuffix(pb, dn)) {
dc8c34
+            newdn = slapi_ch_strdup(newrdn);
dc8c34
+        } else {
dc8c34
+            /* no need to free this pdn. */
dc8c34
+            const char *pdn = slapi_dn_find_parent_ext(dn, is_tombstone);
dc8c34
+            if (pdn) {
dc8c34
+                newdn = slapi_dn_plus_rdn(pdn, newrdn);
dc8c34
+            } else {
dc8c34
+                newdn = slapi_ch_strdup(newrdn);
dc8c34
+            }
dc8c34
         }
dc8c34
-        slapi_ch_free( (void**)&pdn );
dc8c34
     }
dc8c34
     return newdn;
dc8c34
 }
dc8c34
@@ -1611,6 +1752,7 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
dc8c34
     Slapi_Operation *operation;
dc8c34
     int is_ruv = 0;                 /* True if the current entry is RUV */
dc8c34
     int orig_ec_in_cache = 0;
dc8c34
+    int cache_rc = 0;
dc8c34
 
dc8c34
     slapi_pblock_get( pb, SLAPI_BACKEND, &be );
dc8c34
     slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
dc8c34
@@ -1622,7 +1764,12 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
dc8c34
      * Update the ID to Entry index. 
dc8c34
      * Note that id2entry_add replaces the entry, so the Entry ID stays the same.
dc8c34
      */
dc8c34
-    retval = id2entry_add( be, *ec, ptxn );
dc8c34
+    retval = id2entry_add_ext(be, *ec, ptxn, 1, &cache_rc);
dc8c34
+    if (cache_rc) {
dc8c34
+        LDAPDebug(LDAP_DEBUG_CACHE,
dc8c34
+                  "modrdn_rename_entry_update_indexes: adding %s failed to add to the cache (rc: %d, cache_rc: %d)\n",
dc8c34
+                  slapi_entry_get_dn(e->ep_entry), retval, cache_rc);
dc8c34
+    }
dc8c34
     if (DB_LOCK_DEADLOCK == retval)
dc8c34
     {
dc8c34
         /* Retry txn */
dc8c34
@@ -1716,11 +1863,11 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
dc8c34
         }
dc8c34
     }
dc8c34
     if (cache_replace( &inst->inst_cache, e, *ec ) != 0 ) {
dc8c34
-        LDAPDebug0Args( LDAP_DEBUG_BACKLDBM, "modrdn_rename_entry_update_indexes cache_replace failed\n");
dc8c34
+        LDAPDebug2Args(LDAP_DEBUG_CACHE,
dc8c34
+                       "modrdn_rename_entry_update_indexes cache_replace %s -> %s failed\n",
dc8c34
+                       slapi_entry_get_dn(e->ep_entry), slapi_entry_get_dn((*ec)->ep_entry));
dc8c34
         retval= -1;
dc8c34
         goto error_return;
dc8c34
-    } else {
dc8c34
-        *e_in_cache = 0; /* e un-cached */
dc8c34
     }
dc8c34
     if (orig_ec_in_cache) {
dc8c34
         /* ec was already added to the cache via cache_add_tentative (to reserve its spot in the cache)
dc8c34
@@ -1936,7 +2083,8 @@ moddn_get_children(back_txn *ptxn,
dc8c34
                    struct backentry *parententry,
dc8c34
                    Slapi_DN *dn_parentdn,
dc8c34
                    struct backentry ***child_entries,
dc8c34
-                   struct backdn ***child_dns)
dc8c34
+                   struct backdn ***child_dns,
dc8c34
+                   int is_resurect_operation)
dc8c34
 {
dc8c34
     ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
dc8c34
     int err= 0;
dc8c34
@@ -1964,7 +2112,7 @@ moddn_get_children(back_txn *ptxn,
dc8c34
     {
dc8c34
         err = entryrdn_get_subordinates(be,
dc8c34
                         slapi_entry_get_sdn_const(parententry->ep_entry),
dc8c34
-                        parententry->ep_id, &candidates, ptxn);
dc8c34
+                        parententry->ep_id, &candidates, ptxn, is_resurect_operation);
dc8c34
         if (err) {
dc8c34
             LDAPDebug1Arg( LDAP_DEBUG_ANY, "moddn_get_children: "
dc8c34
                            "entryrdn_get_subordinates returned %d\n", err);
dc8c34
@@ -1985,6 +2133,12 @@ moddn_get_children(back_txn *ptxn,
dc8c34
         
dc8c34
     if (candidates!=NULL)
dc8c34
     {
dc8c34
+        Slapi_DN parentsdn = {0};
dc8c34
+        if (is_resurect_operation) {
dc8c34
+            slapi_sdn_get_parent(dn_parentdn, &parentsdn);
dc8c34
+            dn_parentdn = &parentsdn;
dc8c34
+        }
dc8c34
+
dc8c34
         sr_current = idl_iterator_init(candidates);
dc8c34
         result_idl= idl_alloc(candidates->b_nids);
dc8c34
         do
dc8c34
@@ -2017,6 +2171,7 @@ moddn_get_children(back_txn *ptxn,
dc8c34
             }
dc8c34
         } while (id!=NOID);
dc8c34
         idl_free(candidates);
dc8c34
+        slapi_sdn_done(&parentsdn);
dc8c34
     }
dc8c34
     
dc8c34
     nids = result_idl ? result_idl->b_nids : 0;
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
index a097307..746528e 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
@@ -1164,7 +1164,7 @@ subtree_candidates(
dc8c34
             /* subtree-rename: on && no ancestorid */
dc8c34
             *err = entryrdn_get_subordinates(be,
dc8c34
                                          slapi_entry_get_sdn_const(e->ep_entry),
dc8c34
-                                         e->ep_id, &descendants, &txn);
dc8c34
+                                         e->ep_id, &descendants, &txn, 0);
dc8c34
             idl_insert(&descendants, e->ep_id);
dc8c34
             candidates = idl_intersection(be, candidates, descendants);
dc8c34
             idl_free(tmp);
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
dc8c34
index 47e0269..51ff62b 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
dc8c34
@@ -898,7 +898,7 @@ static IDList *ldbm_fetch_subtrees(backend *be, char **include, int *err)
dc8c34
          */
dc8c34
         if (entryrdn_get_noancestorid()) {
dc8c34
             /* subtree-rename: on && no ancestorid */
dc8c34
-            *err = entryrdn_get_subordinates(be, &sdn, id, &idl, txn);
dc8c34
+            *err = entryrdn_get_subordinates(be, &sdn, id, &idl, txn, 0);
dc8c34
         } else {
dc8c34
             *err = ldbm_ancestorid_read(be, txn, id, &idl);
dc8c34
         }
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/parents.c b/ldap/servers/slapd/back-ldbm/parents.c
dc8c34
index 7ca9f24..669eaef 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/parents.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/parents.c
dc8c34
@@ -58,11 +58,17 @@ char *tombstone_numsubordinates = LDBM_TOMBSTONE_NUMSUBORDINATES_STR;
dc8c34
  * The routine is allowed to modify the parent entry, and to return a set of 
dc8c34
  * LDAPMods reflecting the changes it made. The LDAPMods array must be freed 
dc8c34
  * by the called by calling ldap_free_mods(p,1)
dc8c34
+ *
dc8c34
+ *     PARENTUPDATE_RESURECT == turning a tombstone into an entry
dc8c34
+ *                              tombstone_numsubordinates--
dc8c34
+ *                              numsubordinates++
dc8c34
  */
dc8c34
 /* 
dc8c34
- * PARENTUPDATE_CREATE_TOMBSTONE: increment tombstone_numsubordinates
dc8c34
+ * PARENTUPDATE_CREATE_TOMBSTONE: turning an entry into a tombstone
dc8c34
+ *                                numsubordinates--
dc8c34
+ *                                tombstone_numsubordinates++
dc8c34
  * PARENTUPDATE_DELETE_TOMBSTONE: don't touch numsubordinates, and
dc8c34
- *                                decrement tombstone_numsubordinates
dc8c34
+ *                                tombstone_numsubordinates--
dc8c34
  */
dc8c34
 
dc8c34
 int
dc8c34
@@ -84,7 +90,7 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
dc8c34
 	op &= PARENTUPDATE_MASK;
dc8c34
 
dc8c34
 	/* Check nobody is trying to use op == 3, it's not implemented yet */
dc8c34
-	PR_ASSERT( (op == PARENTUPDATE_ADD) || (op == PARENTUPDATE_DEL));
dc8c34
+	PR_ASSERT((op == PARENTUPDATE_ADD) || (op == PARENTUPDATE_DEL) || (op == PARENTUPDATE_RESURECT));
dc8c34
 
dc8c34
 	/* We want to invent a mods set to be passed to modify_apply_mods() */
dc8c34
 
dc8c34
@@ -114,16 +120,17 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
dc8c34
 
dc8c34
 	if (PARENTUPDATE_DELETE_TOMBSTONE != repl_op) {
dc8c34
 		/* are we adding ? */
dc8c34
-		if ( (PARENTUPDATE_ADD == op) && !already_present) {
dc8c34
+		if (((PARENTUPDATE_ADD == op) || (PARENTUPDATE_RESURECT == op)) && !already_present) {
dc8c34
 			/* If so, and the parent entry does not already have a subcount 
dc8c34
 			 * attribute, we need to add it */
dc8c34
 			mod_op = LDAP_MOD_ADD;
dc8c34
 		} else  if (PARENTUPDATE_DEL == op) {
dc8c34
 			if (!already_present) {
dc8c34
 				/* This means that something is wrong---deleting a child but no subcount present on parent */
dc8c34
-				LDAPDebug0Args( LDAP_DEBUG_ANY,
dc8c34
-				                "numsubordinates assertion failure\n" );
dc8c34
+				LDAPDebug(LDAP_DEBUG_ANY, "Parent %s has no children. (op 0x%x, repl_op 0x%x)\n",
dc8c34
+				          slapi_entry_get_dn(mc->old_entry->ep_entry), op, repl_op);
dc8c34
 				slapi_mods_free(&smods);
dc8c34
+				PR_ASSERT(0);
dc8c34
 				return -1;
dc8c34
 			} else {
dc8c34
 				if (current_sub_count == 1) {
dc8c34
@@ -138,7 +145,7 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
dc8c34
 		}
dc8c34
 
dc8c34
 		/* Now compute the new value */
dc8c34
-		if (PARENTUPDATE_ADD == op) {
dc8c34
+		if ((PARENTUPDATE_ADD == op) || (PARENTUPDATE_RESURECT == op)) {
dc8c34
 			current_sub_count++;
dc8c34
 		} else {
dc8c34
 			current_sub_count--;
dc8c34
@@ -159,8 +166,8 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
dc8c34
 
dc8c34
 	/* tombstoneNumSubordinates is needed only when this is repl op
dc8c34
 	 * and a child is being deleted */
dc8c34
-	if (repl_op && (PARENTUPDATE_DEL == op)) {
dc8c34
-		current_sub_count = LDAP_MAXINT;
dc8c34
+	current_sub_count = LDAP_MAXINT;
dc8c34
+	if ((repl_op && (PARENTUPDATE_DEL == op)) || (PARENTUPDATE_RESURECT == op)) {
dc8c34
 		ret = slapi_entry_attr_find(mc->old_entry->ep_entry,
dc8c34
 		                            tombstone_numsubordinates, &read_attr);
dc8c34
 		if (0 == ret) {
dc8c34
@@ -175,7 +182,7 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
dc8c34
 			}
dc8c34
 		}
dc8c34
 
dc8c34
-		if (PARENTUPDATE_DELETE_TOMBSTONE == repl_op) {
dc8c34
+		if ((PARENTUPDATE_DELETE_TOMBSTONE == repl_op) || (PARENTUPDATE_RESURECT == op)) {
dc8c34
 			/* deleting a tombstone entry: 
dc8c34
 			 * reaping or manually deleting it */
dc8c34
 			if ((current_sub_count != LDAP_MAXINT) && 
dc8c34
@@ -187,9 +194,7 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
dc8c34
 				               tombstone_numsubordinates,
dc8c34
 				               strlen(value_buffer), value_buffer);
dc8c34
 			}
dc8c34
-		}
dc8c34
-
dc8c34
-		if (PARENTUPDATE_CREATE_TOMBSTONE == repl_op) {
dc8c34
+		} else if (PARENTUPDATE_CREATE_TOMBSTONE == repl_op) {
dc8c34
 			/* creating a tombstone entry */
dc8c34
 			if (current_sub_count != LDAP_MAXINT) {
dc8c34
 				current_sub_count++;
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
index 02b261b..f3c84a1 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
@@ -190,6 +190,7 @@ struct backentry *dn2entry_ext(Slapi_Backend *be, const Slapi_DN *sdn, back_txn
dc8c34
 struct backentry *dn2entry_or_ancestor(Slapi_Backend *be, const Slapi_DN *sdn, Slapi_DN *ancestor, back_txn *txn, int *err);
dc8c34
 struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
dc8c34
 int get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
dc8c34
+int get_copy_of_entry_ext(Slapi_PBlock *pb, ID id, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
dc8c34
 void done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter);
dc8c34
 
dc8c34
 /*
dc8c34
@@ -699,8 +700,8 @@ int entryrdn_index_entry(backend *be, struct backentry *e, int flags, back_txn *
dc8c34
 int entryrdn_index_read(backend *be, const Slapi_DN *sdn, ID *id, back_txn *txn);
dc8c34
 int
dc8c34
 entryrdn_index_read_ext(backend *be, const Slapi_DN *sdn, ID *id, int flags, back_txn *txn);
dc8c34
-int entryrdn_rename_subtree(backend *be, const Slapi_DN *oldsdn, Slapi_RDN *newsrdn, const Slapi_DN *newsupsdn, ID id, back_txn *txn);
dc8c34
-int entryrdn_get_subordinates(backend *be, const Slapi_DN *sdn, ID id, IDList **subordinates, back_txn *txn);
dc8c34
+int entryrdn_rename_subtree(backend *be, const Slapi_DN *oldsdn, Slapi_RDN *newsrdn, const Slapi_DN *newsupsdn, ID id, back_txn *txn, int flags);
dc8c34
+int entryrdn_get_subordinates(backend *be, const Slapi_DN *sdn, ID id, IDList **subordinates, back_txn *txn, int flags);
dc8c34
 int entryrdn_lookup_dn(backend *be, const char *rdn, ID id, char **dn, back_txn *txn);
dc8c34
 int entryrdn_get_parent(backend *be, const char *rdn, ID id, char **prdn, ID *pid, back_txn *txn);
dc8c34
 #endif
dc8c34
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
dc8c34
index a5a21e0..785256f 100644
dc8c34
--- a/ldap/servers/slapd/entry.c
dc8c34
+++ b/ldap/servers/slapd/entry.c
dc8c34
@@ -3090,9 +3090,10 @@ slapi_entry_add_rdn_values( Slapi_Entry *e )
dc8c34
  * Author/Modifier: RJP
dc8c34
  */
dc8c34
 int
dc8c34
-slapi_entry_has_children(const Slapi_Entry *entry)
dc8c34
+slapi_entry_has_children_ext(const Slapi_Entry *entry, int include_tombstone)
dc8c34
 {
dc8c34
 	Slapi_Attr *attr;
dc8c34
+	int count = 0;
dc8c34
 
dc8c34
 	LDAPDebug( LDAP_DEBUG_TRACE, "=> slapi_has_children( %s )\n", slapi_entry_get_dn_const(entry), 0, 0);
dc8c34
 
dc8c34
@@ -3102,15 +3103,34 @@ slapi_entry_has_children(const Slapi_Entry *entry)
dc8c34
 		Slapi_Value *sval;
dc8c34
 		slapi_attr_first_value( attr, &sval );
dc8c34
 		if(sval!=NULL)
dc8c34
-		{	   
dc8c34
+		{
dc8c34
 			const struct berval *bval = slapi_value_get_berval( sval );
dc8c34
 			if(bval!=NULL)
dc8c34
 			{
dc8c34
 				/* The entry has the attribute, and it's non-zero */
dc8c34
-				if (strcmp(bval->bv_val, "0") != 0)
dc8c34
-				{
dc8c34
-					LDAPDebug( LDAP_DEBUG_TRACE, "<= slapi_has_children 1\n", 0, 0, 0 );
dc8c34
-					return(1);
dc8c34
+				count = strtol(bval->bv_val, (char **)NULL, 10);
dc8c34
+				if (count > 0) {
dc8c34
+					LDAPDebug1Arg( LDAP_DEBUG_TRACE, "<= slapi_has_children %d\n", count);
dc8c34
+					return count;
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
+	}
dc8c34
+	/*If the subordinatecount exists, and it's nonzero, then return 1.*/
dc8c34
+	if (include_tombstone && (slapi_entry_attr_find( entry, "tombstonenumsubordinates", &attr) == 0))
dc8c34
+	{
dc8c34
+		Slapi_Value *sval;
dc8c34
+		slapi_attr_first_value( attr, &sval );
dc8c34
+		if(sval!=NULL)
dc8c34
+		{
dc8c34
+			const struct berval *bval = slapi_value_get_berval( sval );
dc8c34
+			if(bval!=NULL)
dc8c34
+			{
dc8c34
+				/* The entry has the attribute, and it's non-zero */
dc8c34
+				count = strtol(bval->bv_val, (char **)NULL, 10);
dc8c34
+				if (count > 0) {
dc8c34
+					LDAPDebug1Arg( LDAP_DEBUG_TRACE, "<= slapi_has_tombstone_children %d\n", count);
dc8c34
+					return count;
dc8c34
 				}
dc8c34
 			}
dc8c34
 		}
dc8c34
@@ -3119,6 +3139,12 @@ slapi_entry_has_children(const Slapi_Entry *entry)
dc8c34
 	return(0);
dc8c34
 }
dc8c34
 
dc8c34
+int
dc8c34
+slapi_entry_has_children(const Slapi_Entry *entry)
dc8c34
+{
dc8c34
+	return slapi_entry_has_children_ext(entry, 0);
dc8c34
+}
dc8c34
+
dc8c34
 /*
dc8c34
  * Renames an entry to simulate a MODRDN operation
dc8c34
  */
dc8c34
diff --git a/ldap/servers/slapd/rdn.c b/ldap/servers/slapd/rdn.c
dc8c34
index fe2fae0..6e40ed8 100644
dc8c34
--- a/ldap/servers/slapd/rdn.c
dc8c34
+++ b/ldap/servers/slapd/rdn.c
dc8c34
@@ -124,7 +124,7 @@ slapi_rdn_init_dn(Slapi_RDN *rdn,const char *dn)
dc8c34
  *                1 -- "dn" does not belong to the database; could be "rdn"
dc8c34
  */
dc8c34
 static int
dc8c34
-_slapi_rdn_init_all_dn_ext(Slapi_RDN *rdn, const Slapi_DN *sdn)
dc8c34
+_slapi_rdn_init_all_dn_ext(Slapi_RDN *rdn, const Slapi_DN *sdn, int is_tombstone)
dc8c34
 {
dc8c34
 	const char *dn = NULL;
dc8c34
 	const char *ndn= NULL;
dc8c34
@@ -202,9 +202,16 @@ _slapi_rdn_init_all_dn_ext(Slapi_RDN *rdn, const Slapi_DN *sdn)
dc8c34
 	}
dc8c34
 
dc8c34
 	/* Get the last matched position */
dc8c34
-	if(dns)
dc8c34
-	{
dc8c34
-		rdn->rdn = slapi_ch_strdup(dns[0]);
dc8c34
+	if (dns) {
dc8c34
+		if (is_tombstone && slapi_is_special_rdn(dns[0], RDN_IS_TOMBSTONE)) {
dc8c34
+			/* merge nsuniqueid=...,<rdn> into one rdn */
dc8c34
+			rdn->rdn = slapi_ch_smprintf("%s,%s", dns[0], dns[1]);
dc8c34
+			slapi_ch_free_string(&dns[0]);
dc8c34
+			dns[0] = slapi_ch_strdup(rdn->rdn);
dc8c34
+			charray_remove(dns, dns[1], 1);
dc8c34
+		} else {
dc8c34
+			rdn->rdn = slapi_ch_strdup(dns[0]);
dc8c34
+		}
dc8c34
 		rdn->all_rdns = dns;
dc8c34
 		slapi_setbit_uchar(rdn->flag,FLAG_ALL_RDNS);
dc8c34
 	}
dc8c34
@@ -238,7 +245,7 @@ slapi_rdn_init_all_dn(Slapi_RDN *rdn, const char *dn)
dc8c34
 	slapi_rdn_init(rdn);
dc8c34
 	slapi_sdn_init(&sdn;;
dc8c34
 	slapi_sdn_set_dn_byval(&sdn, dn);
dc8c34
-	rc = _slapi_rdn_init_all_dn_ext(rdn, (const Slapi_DN *)&sdn;;
dc8c34
+	rc = _slapi_rdn_init_all_dn_ext(rdn, (const Slapi_DN *)&sdn, 0);
dc8c34
 	slapi_sdn_done(&sdn;;
dc8c34
 	return rc;
dc8c34
 }
dc8c34
@@ -257,6 +264,33 @@ slapi_rdn_init_all_dn(Slapi_RDN *rdn, const char *dn)
dc8c34
  *                1 -- dn does not belong to the database
dc8c34
  */
dc8c34
 int
dc8c34
+slapi_rdn_init_all_sdn_ext(Slapi_RDN *rdn, const Slapi_DN *sdn, int is_tombstone)
dc8c34
+{
dc8c34
+	int rc = 0; /* success */
dc8c34
+
dc8c34
+	if (NULL == rdn || NULL == sdn)
dc8c34
+	{
dc8c34
+		return -1;
dc8c34
+	}
dc8c34
+	slapi_rdn_init(rdn);
dc8c34
+	rc = _slapi_rdn_init_all_dn_ext(rdn, sdn, is_tombstone);
dc8c34
+	return rc;
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ * This function sets DN from sdn to Slapi_RDN.
dc8c34
+ * Note: The underlying function _slapi_rdn_init_all_dn_ext checks if the DN
dc8c34
+ * is in the root or sub suffix the server owns.  If it is, the root or sub
dc8c34
+ * suffix is treated as one "rdn" (e.g., "dc=sub,dc=example,dc=com") and 0 is
dc8c34
+ * returned.  If it is not, the DN is separated by ',' and each string is set
dc8c34
+ * to RDN array. (e.g., input: "uid=A,ou=does_not_exist" ==> "uid=A", "ou=
dc8c34
+ * does_not_exist") and 1 is returned.
dc8c34
+ *
dc8c34
+ * Return Value:  0 -- Success
dc8c34
+ *               -1 -- Error
dc8c34
+ *                1 -- dn does not belong to the database
dc8c34
+ */
dc8c34
+int
dc8c34
 slapi_rdn_init_all_sdn(Slapi_RDN *rdn, const Slapi_DN *sdn)
dc8c34
 {
dc8c34
 	int rc = 0; /* success */
dc8c34
@@ -266,7 +300,7 @@ slapi_rdn_init_all_sdn(Slapi_RDN *rdn, const Slapi_DN *sdn)
dc8c34
 		return -1;
dc8c34
 	}
dc8c34
 	slapi_rdn_init(rdn);
dc8c34
-	rc = _slapi_rdn_init_all_dn_ext(rdn, sdn);
dc8c34
+	rc = _slapi_rdn_init_all_dn_ext(rdn, sdn, 0);
dc8c34
 	return rc;
dc8c34
 }
dc8c34
 
dc8c34
@@ -291,6 +325,17 @@ slapi_rdn_init_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn)
dc8c34
 }
dc8c34
 
dc8c34
 void
dc8c34
+slapi_rdn_set_dn_ext(Slapi_RDN *rdn,const char *dn, int skip_tombstone)
dc8c34
+{
dc8c34
+	const char *mydn = dn;
dc8c34
+	slapi_rdn_done(rdn);
dc8c34
+	if (skip_tombstone && slapi_is_special_rdn(dn, RDN_IS_TOMBSTONE)) {
dc8c34
+		mydn = dn + slapi_uniqueIDRdnSize() + 1/*,*/;
dc8c34
+	}
dc8c34
+	slapi_rdn_init_dn(rdn, mydn);
dc8c34
+}
dc8c34
+
dc8c34
+void
dc8c34
 slapi_rdn_set_dn(Slapi_RDN *rdn,const char *dn)
dc8c34
 {
dc8c34
 	slapi_rdn_done(rdn);
dc8c34
@@ -473,6 +518,33 @@ slapi_rdn_contains(Slapi_RDN *rdn, const char *type, const char *value, size_t l
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
+slapi_rdn_is_multivalued(Slapi_RDN *rdn)
dc8c34
+{
dc8c34
+	char *p = NULL;
dc8c34
+	if (rdn && rdn->rdn) {
dc8c34
+		p = PL_strchr(rdn->rdn, '+');
dc8c34
+	}
dc8c34
+	if (p) {
dc8c34
+		return 1;
dc8c34
+	} else {
dc8c34
+		return 0;
dc8c34
+	}
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ * Return value 1: if rdn is a conflict rdn
dc8c34
+ *              0: otherwise
dc8c34
+ */
dc8c34
+int
dc8c34
+slapi_rdn_is_conflict(Slapi_RDN *rdn)
dc8c34
+{
dc8c34
+	if (!rdn) {
dc8c34
+		return 0;
dc8c34
+	}
dc8c34
+	return slapi_is_special_rdn(slapi_rdn_get_nrdn(rdn), RDN_IS_CONFLICT);
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
 slapi_rdn_add(Slapi_RDN *rdn, const char *type, const char *value)
dc8c34
 {
dc8c34
 	PR_ASSERT(NULL != type);
dc8c34
@@ -484,12 +556,32 @@ slapi_rdn_add(Slapi_RDN *rdn, const char *type, const char *value)
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{
dc8c34
-		/* type=value+rdn '\0' */
dc8c34
-		char *newrdn = slapi_create_dn_string("%s=%s+%s", type, value, rdn->rdn);
dc8c34
+		char *newrdn = NULL;
dc8c34
+		char *rp = rdn->rdn;
dc8c34
+		PRUint32 uniqueidlen = slapi_uniqueIDRdnSize();
dc8c34
+
dc8c34
+		if (slapi_is_special_rdn(rp, RDN_IS_TOMBSTONE)) {
dc8c34
+			char *corerp = rp + uniqueidlen + 1;
dc8c34
+			*(rp + uniqueidlen) = '\0';
dc8c34
+			newrdn = slapi_create_dn_string("%s,%s=%s+%s", rp, type, value, corerp);
dc8c34
+		} else {
dc8c34
+			/* type=value+rdn '\0' */
dc8c34
+			newrdn = slapi_create_dn_string("%s=%s+%s", type, value, rp);
dc8c34
+		}
dc8c34
 		slapi_ch_free_string(&rdn->rdn);
dc8c34
 		rdn->rdn = newrdn;
dc8c34
 	}
dc8c34
 	slapi_unsetbit_uchar(rdn->flag,FLAG_RDNS);
dc8c34
+
dc8c34
+	if (rdn->all_rdns && rdn->all_rdns[0]) {
dc8c34
+		slapi_ch_free_string(&rdn->all_rdns[0]);
dc8c34
+		rdn->all_rdns[0] = slapi_ch_strdup(rdn->rdn);
dc8c34
+	}
dc8c34
+	if (rdn->all_nrdns && rdn->all_nrdns[0]) {
dc8c34
+		slapi_ch_free_string(&rdn->all_nrdns[0]);
dc8c34
+		rdn->all_nrdns[0] = slapi_ch_strdup(rdn->rdn);
dc8c34
+		slapi_dn_ignore_case(rdn->all_nrdns[0]);
dc8c34
+	}
dc8c34
 	return 1;
dc8c34
 }
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
dc8c34
index 80500a5..9e85dc0 100644
dc8c34
--- a/ldap/servers/slapd/slapi-plugin.h
dc8c34
+++ b/ldap/servers/slapd/slapi-plugin.h
dc8c34
@@ -1832,6 +1832,17 @@ int slapi_entry_attr_has_syntax_value(const Slapi_Entry *e, const char *type, co
dc8c34
 int slapi_entry_has_children(const Slapi_Entry *e);
dc8c34
 
dc8c34
 /**
dc8c34
+ * This function determines if the specified entry has child entries
dc8c34
+ * including the tombstoned descendents.
dc8c34
+ *
dc8c34
+ * \param e Entry that you want to test for child entries.
dc8c34
+ * \param include_tombstone If non-zero, check tombstone_subordinates, too.
dc8c34
+ * \return \c 1 if the entry you supply has child entries.
dc8c34
+ * \return \c 0 if the entry you supply has child entries.
dc8c34
+ */
dc8c34
+int slapi_entry_has_children_ext(const Slapi_Entry *e, int include_tombstone);
dc8c34
+
dc8c34
+/**
dc8c34
  * This function determines if an entry is the root DSE.
dc8c34
  *
dc8c34
  * The root DSE is a special entry that contains information about the Directory
dc8c34
@@ -2930,9 +2941,11 @@ void slapi_rdn_init_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn);
dc8c34
  * \see slapi_rdn_set_rdn()
dc8c34
  */
dc8c34
 void slapi_rdn_set_dn(Slapi_RDN *rdn,const char *dn);
dc8c34
+void slapi_rdn_set_dn_ext(Slapi_RDN *rdn,const char *dn, int skip_tombstone);
dc8c34
 Slapi_RDN *slapi_rdn_new_all_dn(const char *dn);
dc8c34
 int slapi_rdn_init_all_dn(Slapi_RDN *rdn, const char *dn);
dc8c34
 int slapi_rdn_init_all_sdn(Slapi_RDN *rdn, const Slapi_DN *sdn);
dc8c34
+int slapi_rdn_init_all_sdn_ext(Slapi_RDN *rdn, const Slapi_DN *sdn, int is_tombstone);
dc8c34
 
dc8c34
 /**
dc8c34
  * Sets the RDN value in a \c Slapi_RDN structure from a \c Slapi_DN.
dc8c34
@@ -3348,6 +3361,24 @@ size_t slapi_rdn_get_size(Slapi_RDN *srdn);
dc8c34
  */
dc8c34
 char * slapi_rdn_get_value(const char *rdn);
dc8c34
 
dc8c34
+/**
dc8c34
+ * Check if the rdn is multivalued or not
dc8c34
+ *
dc8c34
+ * \param rdn A pointer to rdn to exam.
dc8c34
+ * \return 1, if the rdn is multi valued.
dc8c34
+ *         0, if the rdn is simgle valued.
dc8c34
+ */
dc8c34
+int slapi_rdn_is_multivalued(Slapi_RDN *rdn);
dc8c34
+
dc8c34
+/**
dc8c34
+ * Check if the rdn is a conflict rdn or not
dc8c34
+ *
dc8c34
+ * \param rdn A pointer to rdn to exam.
dc8c34
+ * \return 1, if the rdn is a conflict rdn
dc8c34
+ *         0, if the rdn is not a conflict rdn
dc8c34
+ */
dc8c34
+int slapi_rdn_is_conflict(Slapi_RDN *rdn);
dc8c34
+
dc8c34
 /*
dc8c34
  * utility routines for dealing with DNs
dc8c34
  */
dc8c34
@@ -7301,6 +7332,20 @@ char *slapi_pr_strerror( const PRErrorCode prerrno );
dc8c34
  */
dc8c34
 const char *slapi_system_strerror( const int syserrno );
dc8c34
 
dc8c34
+/** Check if rdn is a slecial rdn/dn or not.
dc8c34
+ * 
dc8c34
+ * \param rdn rdn/dn to check
dc8c34
+ * \param flags specify the type: RDN_IS_TOMBSTONE or RDN_IS_CONFLICT or 0
dc8c34
+ *
dc8c34
+ * \return 1 if rdn matches the flag. 
dc8c34
+ *   If flag is IS_TOMBSTONE, returns 1 if rdn is a tombstone rdn/dn.
dc8c34
+ *   If flag is IS_CONFLICT, returns 1 if rdn is a conflict rdn/dn.
dc8c34
+ * \return 0 otherwise
dc8c34
+ */
dc8c34
+#define RDN_IS_TOMBSTONE 0x1
dc8c34
+#define RDN_IS_CONFLICT  0x2
dc8c34
+int slapi_is_special_rdn(const char *rdn, int flag);
dc8c34
+
dc8c34
 #ifdef __cplusplus
dc8c34
 }
dc8c34
 #endif
dc8c34
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
dc8c34
index b9131a5..ecabbe2 100644
dc8c34
--- a/ldap/servers/slapd/slapi-private.h
dc8c34
+++ b/ldap/servers/slapd/slapi-private.h
dc8c34
@@ -997,6 +997,13 @@ int slapi_uniqueIDIsUUID(const Slapi_UniqueID *uId);
dc8c34
  */
dc8c34
 int slapi_uniqueIDSize( void );
dc8c34
 
dc8c34
+/* Name:		slapi_uniqueIDRdnSize
dc8c34
+   Description:	returns size of SLAPI_ATTR_UNIQUEID=slapi_uniqueIDSize()
dc8c34
+   Parameters:  none
dc8c34
+   Return:		size of the string version of "SLAPI_ATTR_UNIQUEID=uniqueID" in bytes
dc8c34
+ */
dc8c34
+int slapi_uniqueIDRdnSize( void );
dc8c34
+
dc8c34
 /* Name:		slapi_uniqueIDDup
dc8c34
    Description:	duplicates an UniqueID object
dc8c34
    Parameters:	uId - id to duplicate
dc8c34
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c
dc8c34
index 0a9d23d..c566512 100644
dc8c34
--- a/ldap/servers/slapd/util.c
dc8c34
+++ b/ldap/servers/slapd/util.c
dc8c34
@@ -1089,3 +1089,70 @@ slapi_str_to_u64(const char *s)
dc8c34
 		(v6 << 36) | (v7 << 32) | (v8 << 28) | (v9 << 24) | (v10 << 20) | (v11 << 16) |
dc8c34
 		(v12 << 12) | (v13 << 8) | (v14 << 4) | v15;
dc8c34
 }
dc8c34
+
dc8c34
+/*
dc8c34
+ * Check if rdn is a slecial rdn/dn or not.
dc8c34
+ * If flag is IS_TOMBSTONE, returns 1 if rdn is a tombstone rdn/dn.
dc8c34
+ * If flag is IS_CONFLICT, returns 1 if rdn is a conflict rdn/dn.
dc8c34
+ * Otherwise returns 0.
dc8c34
+ */
dc8c34
+static int util_uniqueidlen = 0;
dc8c34
+int
dc8c34
+slapi_is_special_rdn(const char *rdn, int flag)
dc8c34
+{
dc8c34
+	char *rp;
dc8c34
+	int plus = 0;
dc8c34
+	if (!util_uniqueidlen) {
dc8c34
+		util_uniqueidlen = SLAPI_ATTR_UNIQUEID_LENGTH + slapi_uniqueIDSize() + 1/*=*/;
dc8c34
+	}
dc8c34
+
dc8c34
+	if ((RDN_IS_TOMBSTONE != flag) && (RDN_IS_CONFLICT != flag)) {
dc8c34
+		LDAPDebug1Arg(LDAP_DEBUG_ANY, "slapi_is_special_rdn: invalid flag %d\n", flag);
dc8c34
+		return 0; /* not a special rdn/dn */
dc8c34
+	}
dc8c34
+	if (!rdn) {
dc8c34
+		LDAPDebug0Args(LDAP_DEBUG_ANY, "slapi_is_special_rdn: NULL rdn\n");
dc8c34
+		return 0; /* not a special rdn/dn */
dc8c34
+	}
dc8c34
+
dc8c34
+	if (strlen(rdn) < util_uniqueidlen) {
dc8c34
+		return 0; /* not a special rdn/dn */
dc8c34
+	}
dc8c34
+	rp = (char *)rdn;
dc8c34
+	while (rp) {
dc8c34
+		char *comma = NULL;
dc8c34
+		if (!PL_strncasecmp(rp, SLAPI_ATTR_UNIQUEID, SLAPI_ATTR_UNIQUEID_LENGTH) &&
dc8c34
+		    (*(rp + SLAPI_ATTR_UNIQUEID_LENGTH) == '=')) {
dc8c34
+			if (RDN_IS_TOMBSTONE == flag) {
dc8c34
+				if ((*(rp + util_uniqueidlen) == ',') ||
dc8c34
+				    (*(rp + util_uniqueidlen) == '\0')) {
dc8c34
+					return 1;
dc8c34
+				} else {
dc8c34
+					return 0;
dc8c34
+				}
dc8c34
+			} else {
dc8c34
+				if ((*(rp + util_uniqueidlen) == '+') ||
dc8c34
+				    (plus && ((*(rp + util_uniqueidlen) == ',') ||
dc8c34
+				              (*(rp + util_uniqueidlen) == '\0')))) {
dc8c34
+					return 1;
dc8c34
+				}
dc8c34
+			}
dc8c34
+		}
dc8c34
+		comma = PL_strchr(rp, ',');
dc8c34
+		rp = PL_strchr(rp, '+');
dc8c34
+		if (rp && (rp < comma)) {
dc8c34
+			plus = 1;
dc8c34
+			rp++;
dc8c34
+		}
dc8c34
+	}
dc8c34
+	return 0;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+slapi_uniqueIDRdnSize()
dc8c34
+{
dc8c34
+	if (!util_uniqueidlen) {
dc8c34
+		util_uniqueidlen = SLAPI_ATTR_UNIQUEID_LENGTH + slapi_uniqueIDSize() + 1/*=*/;
dc8c34
+	}
dc8c34
+	return util_uniqueidlen;
dc8c34
+}
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34