Browse Source

Ticket 49043 - make replication conflicts transparent to clients

Bug Description:
replication conflicts are created mostly because of failures in manually applying updates on different servers or client applications. But once they are created many clients, applications and users have problems to understand and handle them properly

Fix Description:
- keep conflicts but add objectclass ldapsubentry to make them invisible by default
- extend urp handling to handle all conflict casees and have a consistent database on all servers

https://pagure.io/389-ds-base/issue/49043

Reviewed by: Mark, Thierry, William
Ludwig Krispenz 8 years ago
parent
commit
f63949d1fb

+ 1 - 0
Makefile.am

@@ -1197,6 +1197,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \
 	ldap/servers/slapd/pblock.c \
 	ldap/servers/slapd/plugin.c \
 	ldap/servers/slapd/plugin_acl.c \
+	ldap/servers/slapd/plugin_mmr.c \
 	ldap/servers/slapd/plugin_internal_op.c \
 	ldap/servers/slapd/plugin_mr.c \
 	ldap/servers/slapd/plugin_role.c \

+ 1 - 0
ldap/schema/02common.ldif

@@ -129,6 +129,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.3023 NAME 'nsViewFilter' DESC 'Netscape
 attributeTypes: ( 2.16.840.1.113730.3.1.2063 NAME 'nsEncryptionAlgorithm' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2093 NAME 'nsslapd-changelogsuffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2094 NAME 'nsslapd-parent-suffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2401 NAME 'ConflictCSN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
 #
 # objectclasses:
 #

+ 2 - 0
ldap/servers/plugins/replication/repl5.h

@@ -205,6 +205,8 @@ int multimaster_preop_modrdn(Slapi_PBlock *pb);
 int multimaster_preop_search(Slapi_PBlock *pb);
 int multimaster_preop_compare(Slapi_PBlock *pb);
 int multimaster_ruv_search(Slapi_PBlock *pb);
+int multimaster_mmr_preop (Slapi_PBlock *pb, int flags);
+int multimaster_mmr_postop (Slapi_PBlock *pb, int flags);
 int multimaster_bepreop_add(Slapi_PBlock *pb);
 int multimaster_bepreop_delete(Slapi_PBlock *pb);
 int multimaster_bepreop_modify(Slapi_PBlock *pb);

+ 42 - 16
ldap/servers/plugins/replication/repl5_init.c

@@ -109,6 +109,7 @@ static Slapi_PluginDesc multimasterpostopdesc = {"replication-multimaster-postop
 static Slapi_PluginDesc multimasterinternalpreopdesc = {"replication-multimaster-internalpreop", VENDOR, DS_PACKAGE_VERSION, "Multi-master replication internal pre-operation plugin"};
 static Slapi_PluginDesc multimasterinternalpostopdesc = {"replication-multimaster-internalpostop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication internal post-operation plugin"};
 static Slapi_PluginDesc multimasterbepreopdesc = {"replication-multimaster-bepreop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication bepre-operation plugin"};
+static Slapi_PluginDesc multimasterbemmrdesc = {"replication-multimaster-bepreop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication be plugin"};
 static Slapi_PluginDesc multimasterbepostopdesc = {"replication-multimaster-bepostop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication bepost-operation plugin"};
 static Slapi_PluginDesc multimasterbetxnpostopdesc = {"replication-multimaster-betxnpostop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication be transaction post-operation plugin"};
 static Slapi_PluginDesc multimasterextopdesc = {"replication-multimaster-extop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication extended-operation plugin"};
@@ -337,10 +338,6 @@ multimaster_bepreop_init(Slapi_PBlock *pb)
 
     if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 ||
         slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterbepreopdesc) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN, (void *)multimaster_bepreop_add) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN, (void *)multimaster_bepreop_delete) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN, (void *)multimaster_bepreop_modify) != 0 ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_MODRDN_FN, (void *)multimaster_bepreop_modrdn) != 0 ||
         slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_CLOSE_FN, (void *)cl5Close) != 0 ||
         slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_BACKUP_FN, (void *)cl5WriteRUV) != 0) {
         slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_bepreop_init - Failed\n");
@@ -350,6 +347,21 @@ multimaster_bepreop_init(Slapi_PBlock *pb)
     return rc;
 }
 
+int
+multimaster_mmr_init( Slapi_PBlock *pb )
+{
+    int rc= 0; /* OK */
+
+    if(slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+       slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterbemmrdesc ) != 0 ||
+       slapi_pblock_set(pb, SLAPI_PLUGIN_MMR_BETXN_PREOP, (void *) multimaster_mmr_preop ) != 0 ||
+       slapi_pblock_set(pb, SLAPI_PLUGIN_MMR_BETXN_POSTOP, (void *) multimaster_mmr_postop ) != 0) {
+       slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_mmr_init - Failed\n" );
+       rc= -1;
+}
+
+return rc;
+}
 /*
  * betxnpreop: if betxn is on, call preop urp at betxnpreop.
  */
@@ -415,27 +427,35 @@ multimaster_betxnpostop_init(Slapi_PBlock *pb)
     void *mdn_fn;
 
     if (repl5_is_betxn) {
-        add_fn = multimaster_be_betxnpostop_add;
+        /* add_fn = multimaster_be_betxnpostop_add;
         del_fn = multimaster_be_betxnpostop_delete;
         mod_fn = multimaster_be_betxnpostop_modify;
         mdn_fn = multimaster_be_betxnpostop_modrdn;
+        */
+        if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) ||
+            slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
+                             (void *)&multimasterbetxnpostopdesc)) {
+            slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name,
+                          "multimaster_betxnpostop_init - Failed\n");
+            rc = -1;
+        }
     } else {
         add_fn = multimaster_betxnpostop_add;
         del_fn = multimaster_betxnpostop_delete;
         mod_fn = multimaster_betxnpostop_modify;
         mdn_fn = multimaster_betxnpostop_modrdn;
-    }
 
-    if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
-                         (void *)&multimasterbetxnpostopdesc) ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN, add_fn) ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN, del_fn) ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN, mdn_fn) ||
-        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN, mod_fn)) {
-        slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name,
-                      "multimaster_betxnpostop_init - Failed\n");
-        rc = -1;
+        if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) ||
+            slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
+                             (void *)&multimasterbetxnpostopdesc) ||
+            slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN, add_fn) ||
+            slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN, del_fn) ||
+            slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN, mdn_fn) ||
+            slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN, mod_fn)) {
+            slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name,
+                          "multimaster_betxnpostop_init - Failed\n");
+            rc = -1;
+        }
     }
 
     return rc;
@@ -887,6 +907,12 @@ replication_multimaster_plugin_init(Slapi_PBlock *pb)
                                    multimaster_preop_init,
                                    "Multimaster replication preoperation plugin",
                                    NULL, identity);
+        /* Register the main mmr backend plugins */
+        rc = slapi_register_plugin("mmr", 1 /* Enabled */,
+                                   "multimaster_mmr_init",
+                                   multimaster_mmr_init,
+                                   "Multimaster replication be operation plugin",
+                                   NULL, identity);
         /* bepreop: setting SLAPI_TXN_RUV_MODS_FN and cleanup old stateinfo
          * -- should be done before transaction */
         /* if betxn is off, urp is called at bepreop. */

+ 69 - 1
ldap/servers/plugins/replication/repl5_plugins.c

@@ -581,6 +581,54 @@ purge_entry_state_information(Slapi_PBlock *pb)
         object_release(repl_obj);
     }
 }
+int
+
+multimaster_mmr_preop (Slapi_PBlock *pb, int flags)
+{
+	int rc= SLAPI_PLUGIN_SUCCESS;
+
+	switch (flags)
+	{
+	case SLAPI_PLUGIN_BE_PRE_ADD_FN:
+		rc = multimaster_bepreop_add(pb);
+		break;
+	case SLAPI_PLUGIN_BE_PRE_MODIFY_FN:
+		rc = multimaster_bepreop_modify(pb);
+		break;
+	case SLAPI_PLUGIN_BE_PRE_MODRDN_FN:
+		rc = multimaster_bepreop_modrdn(pb);
+		break;
+	case SLAPI_PLUGIN_BE_PRE_DELETE_FN:
+		rc = multimaster_bepreop_delete(pb);
+		break;
+	}
+	return rc;
+}
+
+int
+multimaster_mmr_postop (Slapi_PBlock *pb, int flags)
+{
+	int rc= SLAPI_PLUGIN_SUCCESS;
+
+	switch (flags)
+	{
+	case SLAPI_PLUGIN_BE_TXN_POST_ADD_FN:
+		rc = multimaster_be_betxnpostop_add(pb);
+		break;
+	case SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN:
+		rc = multimaster_be_betxnpostop_delete(pb);
+		break;
+	case SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN:
+		rc = multimaster_be_betxnpostop_modify(pb);
+		break;
+	case SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN:
+		rc = multimaster_be_betxnpostop_modrdn(pb);
+		break;
+	}
+	slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
+                     "multimaster_mmr_postop - error %d for oparation %d.\n", rc, flags);
+	return rc;
+}
 
 /* pure bepreop's -- should be done before transaction starts */
 int
@@ -685,6 +733,18 @@ multimaster_bepreop_modrdn(Slapi_PBlock *pb)
     return rc;
 }
 
+int
+multimaster_bepostop_add(Slapi_PBlock *pb)
+{
+    Slapi_Operation *op;
+
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+    if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) ) {
+        urp_post_add_operation (pb);
+    }
+    return SLAPI_PLUGIN_SUCCESS;
+}
+
 int
 multimaster_bepostop_modrdn(Slapi_PBlock *pb)
 {
@@ -793,6 +853,7 @@ multimaster_be_betxnpostop_add(Slapi_PBlock *pb)
     int rc = 0;
     /* original betxnpost */
     rc = write_changelog_and_ruv(pb);
+    rc |= multimaster_bepostop_add(pb);
     return rc;
 }
 
@@ -1003,16 +1064,23 @@ write_changelog_and_ruv(Slapi_PBlock *pb)
         if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
             op_params->p.p_modify.modify_mods != NULL) {
             void *txn = NULL;
+            char csn_str[CSN_STRSIZE];
             if (cl5_is_diskfull() && !cl5_diskspace_is_available()) {
                 slapi_log_err(SLAPI_LOG_CRIT, repl_plugin_name,
                               "write_changelog_and_ruv - Skipped due to DISKFULL\n");
                 goto common_return;
             }
             slapi_pblock_get(pb, SLAPI_TXN, &txn);
+            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
+                          "write_changelog_and_ruv - Writing change for "
+                          "%s (uniqid: %s, optype: %lu) to changelog csn %s\n",
+                          REPL_GET_DN(&op_params->target_address),
+                          op_params->target_address.uniqueid,
+                          op_params->operation_type,
+                          csn_as_string(op_params->csn, PR_FALSE, csn_str));
             rc = cl5WriteOperationTxn(repl_name, repl_gen, op_params,
                                       !operation_is_flag_set(op, OP_FLAG_REPLICATED), txn);
             if (rc != CL5_SUCCESS) {
-                char csn_str[CSN_STRSIZE];
                 /* ONREPL - log error */
                 slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
                               "write_changelog_and_ruv - Can't add a change for "

+ 2 - 2
ldap/servers/plugins/replication/repl5_ruv.c

@@ -1510,7 +1510,7 @@ ruv_add_csn_inprogress(void *repl, RUV *ruv, const CSN *csn)
     if (ruv_covers_csn_internal(ruv, csn, PR_FALSE)) {
         if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
             slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress - "
-                                                            "The csn %s has already be seen - ignoring\n",
+                          "The csn %s has already be seen (in ruv) - ignoring\n",
                           csn_as_string(csn, PR_FALSE, csn_str));
         }
         rc = RUV_COVERS_CSN;
@@ -1531,7 +1531,7 @@ ruv_add_csn_inprogress(void *repl, RUV *ruv, const CSN *csn)
     {
         if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
             slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress - "
-                                                            "The csn %s has already be seen - ignoring\n",
+                          "The csn %s has already be seen (in csnpl) - ignoring\n",
                           csn_as_string(csn, PR_FALSE, csn_str));
         }
         set_thread_primary_csn(NULL, NULL);

File diff suppressed because it is too large
+ 840 - 104
ldap/servers/plugins/replication/urp.c


+ 6 - 0
ldap/servers/plugins/replication/urp.h

@@ -23,6 +23,7 @@
 int urp_modify_operation(Slapi_PBlock *pb);
 int urp_add_operation(Slapi_PBlock *pb);
 int urp_delete_operation(Slapi_PBlock *pb);
+int urp_post_add_operation(Slapi_PBlock *pb);
 int urp_post_delete_operation(Slapi_PBlock *pb);
 int urp_modrdn_operation(Slapi_PBlock *pb);
 int urp_post_modrdn_operation(Slapi_PBlock *pb);
@@ -33,6 +34,7 @@ int urp_fixup_add_entry(Slapi_Entry *e, const char *target_uniqueid, const char
 int urp_fixup_delete_entry(const char *uniqueid, const char *dn, CSN *opcsn, int opflags);
 int urp_fixup_rename_entry(const Slapi_Entry *entry, const char *newrdn, const char *parentuniqueid, int opflags);
 int urp_fixup_modify_entry(const char *uniqueid, const Slapi_DN *sdn, CSN *opcsn, Slapi_Mods *smods, int opflags);
+int urp_fixup_modrdn_entry(const Slapi_DN *entrydn, const char *newrdn, const Slapi_DN *newsuperior, const char *entryuniqueid, const char *parentuniqueid, CSN *opcsn, int opflags);
 
 int is_suffix_dn(Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn);
 int is_suffix_dn_ext(Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn, int is_tombstone);
@@ -41,6 +43,7 @@ int is_suffix_dn_ext(Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn,
  * urp_glue.c
  */
 int is_glue_entry(const Slapi_Entry *entry);
+int is_conflict_entry(const Slapi_Entry *entry);
 int create_glue_entry(Slapi_PBlock *pb, char *sessionid, Slapi_DN *dn, const char *uniqueid, CSN *opcsn);
 int entry_to_glue(char *sessionid, const Slapi_Entry *entry, const char *reason, CSN *opcsn);
 int glue_to_entry(Slapi_PBlock *pb, Slapi_Entry *entry);
@@ -51,5 +54,8 @@ PRBool get_glue_csn(const Slapi_Entry *entry, const CSN **gluecsn);
  */
 int is_tombstone_entry(const Slapi_Entry *entry);
 int tombstone_to_glue(Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, const Slapi_DN *parentdn, const char *reason, CSN *opcsn, Slapi_DN **newparentdn);
+int tombstone_to_conflict(char *sessionid, Slapi_Entry *entry, const Slapi_DN *conflictdn, const char *reason, CSN *opcsn,     Slapi_DN **newparentdn);
+int conflict_to_tombstone(char *sessionid, Slapi_Entry *entry, CSN *opcsn);
+int tombstone_to_conflict_check_parent( char *sessionid, char *parentdn, const char *uniqueid, const char *parentuniqueid, CSN *opcsn, Slapi_DN *conflictdn);
 int entry_to_tombstone(Slapi_PBlock *pb, Slapi_Entry *entry);
 PRBool get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn);

+ 1 - 1
ldap/servers/plugins/replication/urp_glue.c

@@ -63,7 +63,7 @@ get_glue_csn(const Slapi_Entry *entry, const CSN **gluecsn)
 int
 entry_to_glue(char *sessionid, const Slapi_Entry *entry, const char *reason, CSN *opcsn)
 {
-    int op_result = 0;
+    int op_result = -1;
     const char *dn;
     const Slapi_DN *sdn;
     slapi_mods smods;

+ 205 - 0
ldap/servers/plugins/replication/urp_tombstone.c

@@ -51,6 +51,99 @@ get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn)
     return ists;
 }
 
+static Slapi_DN*
+get_valid_parent_for_conflict(Slapi_Entry *entry)
+{
+	char *replconflict = slapi_entry_attr_get_charptr(entry,ATTR_NSDS5_REPLCONFLICT );
+	char *validdn = NULL;
+	Slapi_DN *valid_DN = NULL;
+
+	if (replconflict) {
+		validdn = strstr(replconflict, " (ADD) ");
+		if (validdn) {
+			validdn += 7;
+			valid_DN = slapi_sdn_new_dn_byval(validdn);
+			slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
+				"get_valid_parent_for_conflict - valid entry dn: %s\n",
+				validdn);
+		}
+		slapi_ch_free_string(&replconflict);
+	}
+	return valid_DN;
+}
+
+int
+tombstone_to_conflict_check_parent (
+	char *sessionid,
+	char *parentdn,
+	const char *uniqueid,
+	const char *parentuniqueid,
+	CSN *opcsn,
+	Slapi_DN *conflictdn)
+{
+	int rc = 0;
+	int op_result;
+	Slapi_PBlock *newpb;
+
+	if (parentdn == 0) {
+		slapi_log_err(SLAPI_LOG_REPL, sessionid,
+				"tombstone_to_conflict_check_parent - no parent entry for: %s\n",
+				slapi_sdn_get_ndn(conflictdn));
+		return rc;
+	} else {
+		slapi_log_err(SLAPI_LOG_REPL, sessionid,
+				"tombstone_to_conflict_check_parent - checking parent entry: %s\n",
+				parentdn);
+	}
+	newpb = slapi_pblock_new();
+	slapi_search_internal_set_pb(
+					newpb,
+					parentdn,
+					LDAP_SCOPE_BASE,
+					"objectclass=*",
+					NULL, /*attrs*/
+					0, /*attrsonly*/
+					NULL, /*Controls*/
+					parentuniqueid, /*uniqueid*/
+					repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+					0);
+	slapi_search_internal_pb(newpb); 
+	slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
+	switch(op_result)
+	{
+	case LDAP_SUCCESS:
+		{
+		Slapi_Entry **entries= NULL;
+		slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+		if(entries!=NULL && entries[0]!=NULL) {
+			if(is_conflict_entry(entries[0])) {
+				Slapi_DN *newsuperior = get_valid_parent_for_conflict(entries[0]);
+				Slapi_RDN *rdn = slapi_rdn_new();
+				slapi_sdn_get_rdn(conflictdn, rdn);
+				const char *newrdn = slapi_rdn_get_rdn(rdn);
+				op_result= urp_fixup_modrdn_entry(
+					conflictdn,
+					newrdn,
+					newsuperior,
+					uniqueid,
+					NULL,
+					NULL,
+					OP_FLAG_NOOP);
+				slapi_rdn_free(&rdn);
+				slapi_sdn_free(&newsuperior);
+			}
+		}
+		}
+		break;
+	default:
+		break;
+	}
+
+	slapi_free_search_results_internal (newpb);
+	slapi_pblock_destroy(newpb);
+	return rc;
+}
+
 static int
 tombstone_to_glue_resolve_parent(
     Slapi_PBlock *pb,
@@ -102,6 +195,118 @@ tombstone_to_glue_resolve_parent(
     return 0;
 }
 
+/*
+ * transform a conflict entry to a tombstone of the original entry
+ * 1. rename the conflict to the original entry
+ * 2. remove conflict attrs
+ * 3. delete it
+ */
+
+int
+conflict_to_tombstone(char *sessionid, Slapi_Entry *entry, CSN *opcsn)
+{
+	int op_result = 0;
+	Slapi_RDN *srdn = slapi_rdn_new();
+	const char *uniqueid = slapi_entry_get_uniqueid ( entry );
+	const char *newrdn = NULL;
+	char *conflictdn = NULL;
+	char *replconflict = slapi_entry_attr_get_charptr(entry,ATTR_NSDS5_REPLCONFLICT );
+
+	if (replconflict) {
+		conflictdn = strstr(replconflict, " (ADD) ");
+		if (conflictdn == NULL) {
+			/* error, wrong type of conflict */
+			op_result = 1;
+		} else {
+			conflictdn += 7;
+			slapi_rdn_init_all_dn(srdn, conflictdn);
+			newrdn = slapi_rdn_get_nrdn(srdn);
+			slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
+				"conflict_to_tombstone - %s - valid entry dn: %s newrdn: %s\n",
+				sessionid, conflictdn, newrdn);
+		}
+	}
+
+	if (op_result) goto done;
+
+	slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
+			"conflict_to_tombstone - %s - Renaming entry %s to %s\n",
+			sessionid, slapi_entry_get_dn_const (entry), newrdn);
+	op_result = urp_fixup_rename_entry(entry, newrdn, NULL, OP_FLAG_NOOP);
+	if (op_result) goto done;
+
+	op_result = urp_fixup_delete_entry (uniqueid, slapi_entry_get_dn_const (entry), opcsn, 0);
+
+done: 
+	slapi_ch_free_string(&replconflict);
+	slapi_rdn_free(&srdn);
+	return op_result;
+}
+
+/*
+ * Convert a tombstone into a conflict entry.
+ */
+int
+tombstone_to_conflict (
+	char *sessionid,
+	Slapi_Entry *tombstoneentry,
+	const Slapi_DN *conflictdn,
+	const char *reason,
+	CSN *opcsn,
+	Slapi_DN **newparentdn)
+{
+	int op_result = 0;
+	Slapi_Mods smods;
+	char csnstr[CSN_STRSIZE+1];
+	char buf[BUFSIZ];
+	char *uniqueid = slapi_entry_attr_get_charptr(tombstoneentry, "nsuiqueid");
+	char *entrydn = slapi_entry_attr_get_charptr(tombstoneentry, "nscpentrydn");
+	char *parentuniqueid = slapi_entry_attr_get_charptr (tombstoneentry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
+	char *parentdn = slapi_dn_parent(slapi_sdn_get_ndn(conflictdn));
+	const CSN *dncsn = entry_get_dncsn(tombstoneentry);
+	csn_as_string(dncsn, PR_FALSE, csnstr);
+
+	slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
+			                 "tombstone_to_conflict - %s - trying to resurrect tombstone as '%s'.\n",
+			                 sessionid, slapi_sdn_get_ndn(conflictdn));
+	slapi_sdn_set_normdn_byval(slapi_entry_get_sdn(tombstoneentry), slapi_sdn_get_ndn(conflictdn));
+	/* not just e_sdn, e_rsdn needs to be updated. */
+	slapi_rdn_set_all_dn(slapi_entry_get_srdn(tombstoneentry), slapi_sdn_get_ndn(conflictdn));
+	op_result = urp_fixup_add_entry (tombstoneentry, NULL, NULL, opcsn, OP_FLAG_RESURECT_ENTRY|OP_FLAG_NOOP);
+
+	if (op_result) {
+		slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
+			"tombstone_to_conflict - %s - Can't resurrect tombstone, error=%d\n",
+			sessionid, op_result);
+		goto done;
+	}
+
+	slapi_mods_init (&smods, 5);
+	slapi_mods_add (&smods, LDAP_MOD_ADD, "objectclass", strlen("ldapsubentry"),"ldapsubentry");
+	slapi_mods_add (&smods, LDAP_MOD_DELETE, "objectclass", strlen("glue"),"glue");
+	slapi_mods_add (&smods, LDAP_MOD_REPLACE, "conflictcsn", strlen(csnstr), csnstr);
+	PR_snprintf (buf, sizeof(buf), "%s (%s) %s",
+	             REASON_ANNOTATE_DN, "ADD", entrydn);
+	slapi_mods_add (&smods, LDAP_MOD_ADD, ATTR_NSDS5_REPLCONFLICT, strlen(buf), buf);
+	op_result = urp_fixup_modify_entry (uniqueid, conflictdn, opcsn, &smods, 0);
+	slapi_mods_done (&smods);
+	if (op_result == LDAP_TYPE_OR_VALUE_EXISTS) {
+		/* the objectclass was already present */
+		op_result = LDAP_SUCCESS;
+	}
+	/* this will go to postop 
+	if (op_result == LDAP_SUCCESS) {
+		op_result = tombstone_to_conflict_check_parent(sessionid, parentdn, uniqueid, parentuniqueid, opcsn, conflictdn);
+	}
+	*/
+done:
+	slapi_ch_free_string(&uniqueid);
+	slapi_ch_free_string(&parentuniqueid);
+	slapi_ch_free_string(&parentdn);
+	slapi_ch_free_string(&entrydn);
+	return op_result;
+}
+
 /*
  * Convert a tombstone into a glue entry.
  */

+ 2 - 1
ldap/servers/plugins/retrocl/retrocl_po.c

@@ -638,7 +638,8 @@ retrocl_postob(Slapi_PBlock *pb, int optype)
         return SLAPI_PLUGIN_SUCCESS;
     }
 
-    if (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)) {
+    if (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY) ||
+        operation_is_flag_set(op, OP_FLAG_NOOP)) {
         slapi_log_err(SLAPI_LOG_TRACE, RETROCL_PLUGIN_NAME, "retrocl_postob - Not applying change for nsTombstone entries\n");
         return SLAPI_PLUGIN_SUCCESS;
     }

+ 134 - 40
ldap/servers/slapd/back-ldbm/ldbm_add.c

@@ -22,6 +22,7 @@ extern char *hassubordinates;
 
 static void delete_update_entrydn_operational_attributes(struct backentry *ep);
 
+static int set_error(Slapi_PBlock *pb, int retval, int ldap_result_code, char **ldap_result_message);
 #define ADD_SET_ERROR(rc, error, count)                                            \
     {                                                                              \
         (rc) = (error);                                                            \
@@ -84,10 +85,12 @@ ldbm_back_add(Slapi_PBlock *pb)
     int is_tombstone_operation = 0;
     int is_fixup_operation = 0;
     int is_remove_from_cache = 0;
+    int op_plugin_call = 1;
     int is_ruv = 0; /* True if the current entry is RUV */
     CSN *opcsn = NULL;
     entry_address addr = {0};
     int not_an_error = 0;
+    int is_noop = 0;
     int parent_switched = 0;
     int noabort = 1;
     int myrc = 0;
@@ -112,6 +115,7 @@ ldbm_back_add(Slapi_PBlock *pb)
     is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP);
     is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV);
     is_remove_from_cache = operation_is_flag_set(operation, OP_FLAG_NEVER_CACHE);
+    if (operation_is_flag_set(operation,OP_FLAG_NOOP)) op_plugin_call = 0;
 
     inst = (ldbm_instance *)be->be_instance_info;
     if (inst && inst->inst_ref_count) {
@@ -321,11 +325,20 @@ ldbm_back_add(Slapi_PBlock *pb)
                 /* Call the Backend Pre Add plugins */
                 ldap_result_code = LDAP_SUCCESS;
                 slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
-                rc = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN);
-                if (rc < 0) {
+                rc = plugin_call_mmr_plugin_preop(pb, NULL,SLAPI_PLUGIN_BE_PRE_ADD_FN);
+                if (rc == 0  && op_plugin_call) {
+                    rc = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN);
+                }
+                if (rc == SLAPI_PLUGIN_NOOP_TOMBSTONE) {
+                    is_tombstone_operation = 1;
+                    is_noop = 1;
+                    op_plugin_call = 0;
+                    rc = LDAP_SUCCESS;
+                } else if (rc < 0) {
                     int opreturn = 0;
                     if (SLAPI_PLUGIN_NOOP == rc) {
                         not_an_error = 1;
+                        is_noop = 1;
                         rc = LDAP_SUCCESS;
                     }
                     /*
@@ -593,6 +606,7 @@ ldbm_back_add(Slapi_PBlock *pb)
                  * next_id will add this id to the list of ids that are pending
                  * id2entry indexing.
                  */
+                Slapi_DN nscpEntrySDN;
                 addingentry = backentry_init(e);
                 if ((addingentry->ep_id = next_id(be)) >= MAXID) {
                     slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_add ",
@@ -630,27 +644,47 @@ ldbm_back_add(Slapi_PBlock *pb)
                      * 3) If the parent entry was found, set the nsparentuniqueid
                      *    attribute to be the unique id of that parent.
                      */
+                    const char *entryuniqueid= slapi_entry_get_uniqueid(addingentry->ep_entry);
                     char *untombstoned_dn = slapi_entry_get_dn(e);
                     char *tombstoned_dn = NULL;
                     if (NULL == untombstoned_dn) {
                         untombstoned_dn = "";
                     }
-                    tombstoned_dn = compute_entry_tombstone_dn(untombstoned_dn, addr.uniqueid);
+                    tombstoned_dn = compute_entry_tombstone_dn(untombstoned_dn, entryuniqueid);
+                    slapi_log_err(SLAPI_LOG_DEBUG,
+                                  "ldbm_back_add", "(tombstone_operation for %s): calculated tombstone_dn "
+                                  "is (%s) \n", entryuniqueid, tombstoned_dn);
                     /*
                      * This needs to be done before slapi_entry_set_dn call,
                      * because untombstoned_dn is released in slapi_entry_set_dn.
                      */
+                    slapi_sdn_init(&nscpEntrySDN);
+                    slapi_sdn_set_ndn_byval(&nscpEntrySDN, slapi_sdn_get_ndn(slapi_entry_get_sdn(addingentry->ep_entry)));
+
                     if (entryrdn_get_switch()) {
-                        Slapi_RDN srdn = {0};
-                        rc = slapi_rdn_init_all_dn(&srdn, tombstoned_dn);
-                        if (rc) {
-                            slapi_log_err(SLAPI_LOG_TRACE,
-                                          "ldbm_back_add", "(tombstone_operation): failed to "
-                                                           "decompose %s to Slapi_RDN\n",
-                                          tombstoned_dn);
+                        if (is_ruv) {
+                            Slapi_RDN srdn = {0};
+                            rc = slapi_rdn_init_all_dn(&srdn, tombstoned_dn);
+                            if (rc) {
+                                slapi_log_err(SLAPI_LOG_TRACE,
+                                              "ldbm_back_add", "(tombstone_operation): failed to "
+                                              "decompose %s to Slapi_RDN\n", tombstoned_dn);
+                            } else {
+                                slapi_entry_set_srdn(e, &srdn);
+                                slapi_rdn_done(&srdn);
+                            }
                         } else {
-                            slapi_entry_set_srdn(e, &srdn);
-                            slapi_rdn_done(&srdn);
+                            /* immediate entry to tombstone */
+                            Slapi_RDN *srdn = slapi_entry_get_srdn(addingentry->ep_entry);
+                            slapi_rdn_init_all_sdn(srdn, slapi_entry_get_sdn_const(addingentry->ep_entry));
+                            char *tombstone_rdn = compute_entry_tombstone_rdn(slapi_entry_get_rdn_const(addingentry->ep_entry),
+                                                                              entryuniqueid);
+                            slapi_log_err(SLAPI_LOG_DEBUG,
+                                          "ldbm_back_add", "(tombstone_operation for %s): calculated tombstone_rdn "
+                                          "is (%s) \n", entryuniqueid, tombstone_rdn);
+                            /* e_srdn has "uniaqueid=..., <ORIG RDN>" */
+                            slapi_rdn_replace_rdn(srdn, tombstone_rdn);
+                            slapi_ch_free_string(&tombstone_rdn);
                         }
                     }
                     slapi_entry_set_dn(addingentry->ep_entry, tombstoned_dn);
@@ -682,11 +716,21 @@ ldbm_back_add(Slapi_PBlock *pb)
                         }
                     }
 
+                    if (attrlist_find( addingentry->ep_entry->e_attrs, SLAPI_ATTR_NSCP_ENTRYDN ) == NULL){
+                        slapi_entry_add_string(addingentry->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(&nscpEntrySDN));
+                    }
+
                     if (NULL != operation->o_params.p.p_add.parentuniqueid) {
                         slapi_entry_add_string(addingentry->ep_entry,
                                                SLAPI_ATTR_VALUE_PARENT_UNIQUEID,
                                                operation->o_params.p.p_add.parentuniqueid);
                     }
+                } else {
+                        /* if an entry is explicitely added as tombstone the entry flag has to be set */
+                        if (slapi_entry_attr_hasvalue(addingentry->ep_entry,
+                                                      SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE)) {
+                            slapi_entry_set_flag(addingentry->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
+                        }
                 }
             }
 
@@ -719,8 +763,12 @@ ldbm_back_add(Slapi_PBlock *pb)
                 pid = parententry->ep_id;
 
                 /* We may need to adjust the DN since parent could be a resurrected conflict entry... */
-                if (!slapi_sdn_isparent(slapi_entry_get_sdn_const(parententry->ep_entry),
-                                        slapi_entry_get_sdn_const(addingentry->ep_entry))) {
+                /* TBD better handle tombstone parents, 
+                 * we have the entry dn as nsuniqueid=nnnn,<rdn>,parentdn
+                 * so is parent will return false
+                 */ 
+                 if (!is_tombstone_operation && !slapi_sdn_isparent(slapi_entry_get_sdn_const(parententry->ep_entry),
+                                                                    slapi_entry_get_sdn_const(addingentry->ep_entry))) {
                     Slapi_DN adjustedsdn = {0};
                     char *adjusteddn = slapi_ch_smprintf("%s,%s",
                                                          slapi_entry_get_rdn_const(addingentry->ep_entry),
@@ -748,12 +796,20 @@ ldbm_back_add(Slapi_PBlock *pb)
             } else if (is_tombstone_operation) {
                 /* Remove the entrydn operational attributes from the addingentry */
                 delete_update_entrydn_operational_attributes(addingentry);
+                if (!is_ruv) {
+                    add_update_entry_operational_attributes(addingentry, pid);
+                }
             } else {
                 /*
                  * add the parentid, entryid and entrydn operational attributes
                  */
                 add_update_entry_operational_attributes(addingentry, pid);
             }
+            if (is_resurect_operation && tombstoneentry && cache_is_in_cache(&inst->inst_cache, tombstoneentry)) {
+                /* we need to remove the tombstone from the cacehr otherwise we have two dns with the same id */
+                cache_unlock_entry(&inst->inst_cache, tombstoneentry);
+                CACHE_RETURN(&inst->inst_cache, &tombstoneentry);
+            }
 
             /* Tentatively add the entry to the cache.  We do this after adding any
              * operational attributes to ensure that the cache is sized correctly. */
@@ -805,31 +861,40 @@ ldbm_back_add(Slapi_PBlock *pb)
 
         /* call the transaction pre add plugins just after the to-be-added entry
          * is prepared. */
-        retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN);
-        if (retval) {
-            int opreturn = 0;
-            if (SLAPI_PLUGIN_NOOP == retval) {
-                not_an_error = 1;
-                rc = retval = LDAP_SUCCESS;
-            }
-            slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_add", "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin "
-                                                            "returned error code %d\n",
-                          retval);
-            if (!ldap_result_code) {
-                slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
-            }
-            if (!ldap_result_code) {
-                ldap_result_code = LDAP_OPERATIONS_ERROR;
-                slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
-            }
-            slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
-            if (!opreturn) {
-                slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
+        if (op_plugin_call) {
+            retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN);
+            if (retval) {
+                int opreturn = 0;
+                if (SLAPI_PLUGIN_NOOP == retval) {
+                    not_an_error = 1;
+                    rc = retval = LDAP_SUCCESS;
+                }
+                slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_add", "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin "
+                                                                "returned error code %d\n",
+                              retval);
+                if (!ldap_result_code) {
+                    slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+                }
+                if (!ldap_result_code) {
+                    ldap_result_code = LDAP_OPERATIONS_ERROR;
+                    slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+                }
+                slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
+                if (!opreturn) {
+                    slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
+                }
+                slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
+                slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_back_add", "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin failed: %d\n",
+                              ldap_result_code ? ldap_result_code : retval);
+                goto error_return;
             }
-            slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-            slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_back_add", "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin failed: %d\n",
-                          ldap_result_code ? ldap_result_code : retval);
-            goto error_return;
+        }
+        if (is_tombstone_operation) {
+            int len = 0;
+            const char *rs = slapi_entry_get_rdn_const(addingentry->ep_entry);
+            char *es= slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO | SLAPI_DUMP_UNIQUEID);
+            slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_back_add", "now adding entry: %s\n %s\n", rs?rs:"no rdn", es);
+            slapi_ch_free_string(&es);
         }
 
         retval = id2entry_add_ext(be, addingentry, &txn, 1, &myrc);
@@ -1113,7 +1178,7 @@ ldbm_back_add(Slapi_PBlock *pb)
     }
 
     /* call the transaction post add plugins just before the commit */
-    if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN))) {
+    if (op_plugin_call && (retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN))) {
         int opreturn = 0;
         slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_add",
                       "SLAPI_PLUGIN_BE_TXN_POST_ADD_FN plugin "
@@ -1134,6 +1199,12 @@ ldbm_back_add(Slapi_PBlock *pb)
         goto error_return;
     }
 
+    retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_ADD_FN);
+    if (retval) {
+        set_error(pb, retval, ldap_result_code, &ldap_result_message);
+        goto error_return;
+    }
+
     /* Release SERIAL LOCK */
     retval = dblayer_txn_commit(be, &txn);
     /* after commit - txn is no longer valid - replace SLAPI_TXN with parent */
@@ -1206,7 +1277,8 @@ diskfull_return:
                 slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &val);
             }
             /* call the transaction post add plugins just before the abort */
-            if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN))) {
+            /* but only if it is not a NOOP */
+            if (!is_noop && op_plugin_call && (retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN))) {
                 int opreturn = 0;
                 slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_add",
                               "SLAPI_PLUGIN_BE_TXN_POST_ADD_FN plugin "
@@ -1222,6 +1294,8 @@ diskfull_return:
                 }
                 slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
             }
+            /* the repl postop needs to be called for aborted operations */
+            retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_ADD_FN);
             if (addingentry) {
                 if (inst && cache_is_in_cache(&inst->inst_cache, addingentry)) {
                     CACHE_REMOVE(&inst->inst_cache, addingentry);
@@ -1396,3 +1470,23 @@ delete_update_entrydn_operational_attributes(struct backentry *ep)
     /* entrydn */
     slapi_entry_attr_delete(ep->ep_entry, LDBM_ENTRYDN_STR);
 }
+
+static int
+set_error(Slapi_PBlock *pb, int retval, int ldap_result_code, char **ldap_result_message)
+{
+    int opreturn = 0;
+    if (!ldap_result_code) {
+        slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+    }
+    if (!ldap_result_code) {
+        ldap_result_code = LDAP_OPERATIONS_ERROR;
+        slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+    }
+    slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
+    if (!opreturn) {
+        slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
+    }
+    slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
+
+    return opreturn;
+}

+ 112 - 72
ldap/servers/slapd/back-ldbm/ldbm_delete.c

@@ -249,9 +249,8 @@ ldbm_back_delete(Slapi_PBlock *pb)
             retval = dblayer_txn_begin_ext(li, parent_txn, &txn, PR_FALSE);
         }
         if (0 != retval) {
-            if (LDBM_OS_ERR_IS_DISKFULL(retval))
-                disk_full = 1;
-            ldap_result_code = LDAP_OPERATIONS_ERROR;
+            if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+            ldap_result_code= LDAP_OPERATIONS_ERROR;
             goto error_return;
         }
 
@@ -260,16 +259,18 @@ ldbm_back_delete(Slapi_PBlock *pb)
 
         if (0 == retry_count) { /* just once */
             /* find and lock the entry we are about to modify */
-            /*
-             * A corner case:
-             * If a conflict occurred in a MMR topology, a replicated delete
+            /* 
+             * A corner case: 
+             * If a conflict occurred in a MMR topology, a replicated delete 
              * op from another master could target a conflict entry; while the
-             * corresponding entry on this server could have been already
+             * corresponding entry on this server could have been already 
              * deleted.  That is, the entry 'e' found with "addr" is a tomb-
              * stone.  If it is the case, we need to back off.
              */
-            if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL) {
-                ldap_result_code = LDAP_NO_SUCH_OBJECT;
+replace_entry:
+            if ((e = find_entry2modify(pb, be, addr, &txn, &result_sent)) == NULL)
+            {
+                ldap_result_code= LDAP_NO_SUCH_OBJECT;
                 retval = -1;
                 slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_delete", "Deleting entry is already deleted.\n");
                 goto error_return; /* error result sent by find_entry2modify() */
@@ -279,56 +280,92 @@ ldbm_back_delete(Slapi_PBlock *pb)
             /* JCMACL - Shouldn't the access check be before the has children check...
              * otherwise we're revealing the fact that an entry exists and has children */
             /* Before has children to mask the presence of children disclosure. */
-            ldap_result_code = plugin_call_acl_plugin(pb, e->ep_entry, NULL, NULL, SLAPI_ACL_DELETE,
-                                                      ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
-            if (ldap_result_code != LDAP_SUCCESS) {
-                ldap_result_message = errbuf;
+            ldap_result_code = plugin_call_acl_plugin (pb, e->ep_entry, NULL, NULL, SLAPI_ACL_DELETE, 
+                                                       ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
+            if ( ldap_result_code != LDAP_SUCCESS ) {
+                ldap_result_message= errbuf;
                 retval = -1;
                 goto error_return;
             }
-
+            /* this has to be handled by urp for replicated operations */
             retval = slapi_entry_has_children(e->ep_entry);
-            if (retval) {
-                ldap_result_code = LDAP_NOT_ALLOWED_ON_NONLEAF;
-                slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
-                              "conn=%lu op=%d Deleting entry %s has %d children.\n",
-                              conn_id, op_id, slapi_entry_get_dn(e->ep_entry), retval);
+            if (retval && !is_replicated_operation) {
+                ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
+                slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_delete", 
+                              "conn=%lu op=%d Deleting entry %s has %d children.\n", 
+                               conn_id, op_id, slapi_entry_get_dn(e->ep_entry), retval);
                 retval = -1;
                 goto error_return;
             }
 
             /* Don't call pre-op for Tombstone entries */
             if (!delete_tombstone_entry) {
-                /*
+                /* 
                  * Some present state information is passed through the PBlock to the
                  * backend pre-op plugin. To ensure a consistent snapshot of this state
                  * we wrap the reading of the entry with the dblock.
                  */
-                ldap_result_code = get_copy_of_entry(pb, addr, &txn,
-                                                     SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
+                ldap_result_code= get_copy_of_entry(pb, addr, &txn,
+                                                    SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
                 free_delete_existing_entry = 1;
-                if (ldap_result_code == LDAP_OPERATIONS_ERROR ||
-                    ldap_result_code == LDAP_INVALID_DN_SYNTAX) {
+                if(ldap_result_code==LDAP_OPERATIONS_ERROR ||
+                   ldap_result_code==LDAP_INVALID_DN_SYNTAX) {
                     /* restore original entry so the front-end delete code can free it */
                     retval = -1;
                     goto error_return;
                 }
                 slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 
-                retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN);
-                if (retval) {
-                    if (SLAPI_PLUGIN_NOOP == retval) {
-                        not_an_error = 1;
-                        rc = LDAP_SUCCESS;
+                retval = plugin_call_mmr_plugin_preop(pb, NULL,SLAPI_PLUGIN_BE_PRE_DELETE_FN);
+                if (SLAPI_PLUGIN_NOOP == retval) {
+                    not_an_error = 1;
+                    rc = LDAP_SUCCESS;
+                } else if (SLAPI_PLUGIN_NOOP_COMMIT == retval) {
+                    not_an_error = 1;
+                    rc = LDAP_SUCCESS;
+                    retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN);
+                    goto commit_return;
+                } else if(slapi_isbitset_int(retval,SLAPI_RTN_BIT_FETCH_EXISTING_UNIQUEID_ENTRY)) {
+                    /* we need to delete an other entry, determined by urp */
+                    done_with_pblock_entry(pb,SLAPI_DELETE_EXISTING_ENTRY); /* Could be through this multiple times */
+                    if (cache_is_in_cache(&inst->inst_cache, e)) {
+                        ep_id = e->ep_id; /* Otherwise, e might have been freed. */
+                        CACHE_REMOVE(&inst->inst_cache, e);
                     }
+                    cache_unlock_entry(&inst->inst_cache, e);
+                    CACHE_RETURN(&inst->inst_cache, &e);
                     /*
+                     * e is unlocked and no longer in cache.
+                     * It could be freed at any moment.
+                     */
+                    e = NULL;
+                    goto replace_entry;
+                } else if(slapi_isbitset_int(retval,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY)) {
+                    Slapi_Entry *e_to_delete = NULL;
+                    done_with_pblock_entry(pb,SLAPI_DELETE_EXISTING_ENTRY); /* Could be through this multiple times */
+                    slapi_log_err(SLAPI_LOG_REPL,
+                                   "ldbm_back_delete", "reloading existing entry "
+                                   "(%s)\n", addr->uniqueid );
+                    ldap_result_code= get_copy_of_entry(pb, addr, &txn,
+                                SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
+                    slapi_pblock_get(pb,SLAPI_DELETE_EXISTING_ENTRY, &e_to_delete);
+                    slapi_entry_free( e->ep_entry );
+                    e->ep_entry = slapi_entry_dup( e_to_delete );
+                    retval = 0;
+                }
+                if (retval == 0) {
+                    retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN);
+                }
+                if (retval)
+                {
+                    /* 
                      * Plugin indicated some kind of failure,
                      * or that this Operation became a No-Op.
                      */
                     slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
                     if (!ldap_result_code) {
                         if (LDAP_ALREADY_EXISTS == ldap_result_code) {
-                            /*
+                            /* 
                              * The target entry is already a tombstone.
                              * We need to treat this as a success,
                              * but we need to remove the entry e from the entry cache.
@@ -339,9 +376,9 @@ ldbm_back_delete(Slapi_PBlock *pb)
                         slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
                     }
                     /* restore original entry so the front-end delete code can free it */
-                    slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
+                    slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &opreturn );
                     if (!opreturn) {
-                        slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &rc);
+                        slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &rc );
                     }
                     slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
                     goto error_return;
@@ -350,7 +387,7 @@ ldbm_back_delete(Slapi_PBlock *pb)
                 delete_tombstone_entry = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_ENTRY);
             }
 
-            /* call the transaction pre delete plugins just after the
+            /* call the transaction pre delete plugins just after the 
              * to-be-deleted entry is prepared. */
             /* these should not need to modify the entry to be deleted -
                if for some reason they ever do, do not use e->ep_entry since
@@ -360,18 +397,18 @@ ldbm_back_delete(Slapi_PBlock *pb)
                 retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN);
                 if (retval) {
                     slapi_log_err(SLAPI_LOG_TRACE,
-                                  "ldbm_back_delete", "SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN plugin "
-                                                      "returned error code %d\n",
-                                  retval);
+                                   "ldbm_back_delete", "SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN plugin "
+                                   "returned error code %d\n", retval );
                     if (!ldap_result_code) {
                         slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
                     }
                     if (!opreturn) {
-                        slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
+                        slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &opreturn );
                     }
                     if (!opreturn) {
-                        slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN,
-                                         ldap_result_code ? &ldap_result_code : &retval);
+                        slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN,
+                                          ldap_result_code ?
+                                          &ldap_result_code : &retval );
                     }
                     slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
                     goto error_return;
@@ -386,13 +423,13 @@ ldbm_back_delete(Slapi_PBlock *pb)
             if (delete_tombstone_entry) {
                 if (!is_tombstone_entry) {
                     slapi_log_err(SLAPI_LOG_WARNING, "ldbm_back_delete",
-                                  "Attempt to delete a non-tombstone entry %s\n", dn);
+                            "Attempt to delete a non-tombstone entry %s\n", dn);
                     delete_tombstone_entry = 0;
                 }
             } else {
-                if (is_tombstone_entry) {
+                if (is_tombstone_entry) { 
                     slapi_log_err(SLAPI_LOG_WARNING, "ldbm_back_delete",
-                                  "Attempt to Tombstone again a tombstone entry %s\n", dn);
+                            "Attempt to Tombstone again a tombstone entry %s\n", dn);
                     delete_tombstone_entry = 1;
                 }
             }
@@ -401,7 +438,7 @@ ldbm_back_delete(Slapi_PBlock *pb)
              * If a CSN is set, we need to tombstone the entry,
              * rather than deleting it outright.
              */
-            opcsn = operation_get_csn(operation);
+            opcsn = operation_get_csn (operation);
             if (!delete_tombstone_entry) {
                 if ((opcsn == NULL) && !is_fixup_operation && operation->o_csngen_handler) {
                     /*
@@ -409,36 +446,35 @@ ldbm_back_delete(Slapi_PBlock *pb)
                      * by entry_assign_operation_csn() if the dn is in an
                      * updatable replica.
                      */
-                    opcsn = entry_assign_operation_csn(pb, e->ep_entry, NULL);
+                    opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL );
                 }
                 if (opcsn != NULL) {
                     if (!is_fixup_operation) {
-                        entry_set_maxcsn(e->ep_entry, opcsn);
+                        entry_set_maxcsn (e->ep_entry, opcsn);
                     }
                 }
                 /*
                  * We are dealing with replication and if we haven't been called to
                  * remove a tombstone, then it's because  we want to create a new one.
                  */
-                if (slapi_operation_get_replica_attr(pb, operation, "nsds5ReplicaTombstonePurgeInterval",
-                                                     &create_tombstone_entry) == 0) {
+                if ( slapi_operation_get_replica_attr (pb, operation, "nsds5ReplicaTombstonePurgeInterval",
+                                                       &create_tombstone_entry) == 0 ) {
                     create_tombstone_entry = (create_tombstone_entry < 0) ? 0 : 1;
                 }
             }
             if (create_tombstone_entry && is_tombstone_entry) {
                 slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_delete",
-                              "Attempt to convert a tombstone entry %s to tombstone\n", dn);
+                    "Attempt to convert a tombstone entry %s to tombstone\n", dn);
                 retval = -1;
                 ldap_result_code = LDAP_UNWILLING_TO_PERFORM;
                 goto error_return;
             }
-
+        
 #ifdef DEBUG
             slapi_log_err(SLAPI_LOG_REPL, "ldbm_back_delete",
-                          "entry: %s  - flags: delete %d is_tombstone_entry %d create %d \n",
-                          dn, delete_tombstone_entry, is_tombstone_entry, create_tombstone_entry);
+                    "entry: %s  - flags: delete %d is_tombstone_entry %d create %d \n",
+                    dn, delete_tombstone_entry, is_tombstone_entry, create_tombstone_entry);
 #endif
-
             /* Save away a copy of the entry, before modifications */
             slapi_pblock_set(pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup(e->ep_entry));
 
@@ -1193,6 +1229,15 @@ ldbm_back_delete(Slapi_PBlock *pb)
         }
     }
 
+    if (rc == 0 && opcsn && !is_fixup_operation && !delete_tombstone_entry) {
+        /* URP Naming Collision
+         * When an entry is deleted by a replicated delete operation
+         * we must check for entries that have had a naming collision
+         * with this entry. Now that this name has been given up, one
+         * of those entries can take over the name.
+         */
+        slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN, slapi_ch_strdup(dn));
+    }
     /* call the transaction post delete plugins just before the commit */
     if (!delete_tombstone_entry &&
         plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN)) {
@@ -1219,7 +1264,20 @@ ldbm_back_delete(Slapi_PBlock *pb)
         slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
         goto error_return;
     }
+    if (parent_found) {
+        /* Replace the old parent entry with the newly modified one */
+        myrc = modify_switch_entries(&parent_modify_c, be);
+        slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
+                      "conn=%lu op=%d modify_switch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+                      conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
+        if (myrc == 0) {
+            parent_switched = 1;
+        }
+    }
 
+    retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN);
+
+commit_return:
     /* Release SERIAL LOCK */
     retval = dblayer_txn_commit(be, &txn);
     /* after commit - txn is no longer valid - replace SLAPI_TXN with parent */
@@ -1282,17 +1340,6 @@ ldbm_back_delete(Slapi_PBlock *pb)
         }
     }
 
-    if (parent_found) {
-        /* Replace the old parent entry with the newly modified one */
-        myrc = modify_switch_entries(&parent_modify_c, be);
-        slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
-                      "conn=%lu op=%d modify_switch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
-                      conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
-        if (myrc == 0) {
-            parent_switched = 1;
-        }
-    }
-
     rc = 0;
     goto common_return;
 
@@ -1361,6 +1408,7 @@ error_return:
             }
             slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
         }
+        retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN);
 
         /* Release SERIAL LOCK */
         dblayer_txn_abort(be, &txn); /* abort crashes in case disk full */
@@ -1378,6 +1426,7 @@ error_return:
                       "conn=%lu op=%d modify_unswitch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
                       conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
     }
+
 common_return:
     if (orig_entry) {
         /* NOTE: #define SLAPI_DELETE_BEPREOP_ENTRY SLAPI_ENTRY_PRE_OP */
@@ -1457,15 +1506,6 @@ diskfull_return:
                   conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry,
                   cache_is_in_cache(&inst->inst_cache, parent_modify_c.new_entry));
     myrc = modify_term(&parent_modify_c, be);
-    if (rc == 0 && opcsn && !is_fixup_operation && !delete_tombstone_entry) {
-        /* URP Naming Collision
-         * When an entry is deleted by a replicated delete operation
-         * we must check for entries that have had a naming collision
-         * with this entry. Now that this name has been given up, one
-         * of those entries can take over the name.
-         */
-        slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN, slapi_ch_strdup(dn));
-    }
     if (free_delete_existing_entry) {
         done_with_pblock_entry(pb, SLAPI_DELETE_EXISTING_ENTRY);
     } else { /* owned by someone else */

+ 9 - 2
ldap/servers/slapd/back-ldbm/ldbm_modify.c

@@ -408,6 +408,7 @@ ldbm_back_modify(Slapi_PBlock *pb)
     int opreturn = 0;
     int mod_count = 0;
     int not_an_error = 0;
+    int is_noop = 0;
     int fixup_tombstone = 0;
     int ec_locked = 0;
     int result_sent = 0;
@@ -622,7 +623,10 @@ ldbm_back_modify(Slapi_PBlock *pb)
             slapi_pblock_set(pb, SLAPI_MODIFY_EXISTING_ENTRY, ec->ep_entry);
             slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 
-            opreturn = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN);
+            opreturn = plugin_call_mmr_plugin_preop(pb, NULL,SLAPI_PLUGIN_BE_PRE_MODIFY_FN);
+            if (opreturn == 0) {
+                opreturn = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN);
+            }
             if (opreturn ||
                 (slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code) && ldap_result_code) ||
                 (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn) && opreturn)) {
@@ -636,6 +640,7 @@ ldbm_back_modify(Slapi_PBlock *pb)
                 }
                 if (SLAPI_PLUGIN_NOOP == opreturn) {
                     not_an_error = 1;
+                    is_noop = 1;
                     rc = opreturn = LDAP_SUCCESS;
                 } else if (!opreturn) {
                     opreturn = SLAPI_PLUGIN_FAILURE;
@@ -861,6 +866,7 @@ ldbm_back_modify(Slapi_PBlock *pb)
         slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
         goto error_return;
     }
+    retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN);
 
     /* Release SERIAL LOCK */
     retval = dblayer_txn_commit(be, &txn);
@@ -911,7 +917,7 @@ error_return:
                and skip processing if they don't want do anything - some plugins that
                keep track of a counter (usn, dna) may want to "rollback" the counter
                in this case */
-            if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) {
+            if (!is_noop && (retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) {
                 slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify",
                               "SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin returned error code %d\n", retval);
                 slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
@@ -921,6 +927,7 @@ error_return:
                     slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
                 }
             }
+            retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN);
 
             /* It is safer not to abort when the transaction is not started. */
             /* Release SERIAL LOCK */

+ 11 - 6
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c

@@ -428,7 +428,10 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
                 }
                 /* Call the Backend Pre ModRDN plugins */
                 slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
-                rc = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODRDN_FN);
+                rc = plugin_call_mmr_plugin_preop(pb, NULL,SLAPI_PLUGIN_BE_PRE_MODRDN_FN);
+                if (rc == 0) {
+                    rc= plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODRDN_FN);
+                }
                 if (rc < 0) {
                     if (SLAPI_PLUGIN_NOOP == rc) {
                         not_an_error = 1;
@@ -1179,6 +1182,10 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
                       conn_id, op_id, parent_modify_context.old_entry, parent_modify_context.new_entry, myrc);
     }
 
+    if (retval == 0 && opcsn != NULL && !is_fixup_operation) {
+        slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN,
+                         slapi_ch_strdup(slapi_sdn_get_dn(sdn)));
+    }
     slapi_pblock_set(pb, SLAPI_ENTRY_POST_OP, postentry);
     /* call the transaction post modrdn plugins just before the commit */
     if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN))) {
@@ -1203,6 +1210,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
         slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
         goto error_return;
     }
+	retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN);
 
     /* Release SERIAL LOCK */
     retval = dblayer_txn_commit(be, &txn);
@@ -1342,6 +1350,7 @@ error_return:
                 }
                 slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
             }
+	retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN);
 
             /* Release SERIAL LOCK */
             dblayer_txn_abort(be, &txn); /* abort crashes in case disk full */
@@ -1464,11 +1473,7 @@ common_return:
     backentry_free(&original_entry);
     backentry_free(&tmpentry);
     slapi_entry_free(original_targetentry);
-    slapi_ch_free((void **)&errbuf);
-    if (retval == 0 && opcsn != NULL && !is_fixup_operation) {
-        slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN,
-                         slapi_ch_strdup(slapi_sdn_get_dn(sdn)));
-    }
+    slapi_ch_free((void**)&errbuf);
     if (pb_conn) {
         slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modrdn",
                       "leave conn=%" PRIu64 " op=%d\n",

+ 1 - 1
ldap/servers/slapd/libmakefile

@@ -53,7 +53,7 @@ LIBSLAPD_OBJS=plugin_role.o getfilelist.o libglobs.o log.o ch_malloc.o entry.o p
 	lenstr.o eventq.o uuid.o uniqueid.o uniqueidgen.o \
 	csngen.o utf8compare.o entrywsi.o valueset.o \
 	attrsyntax.o opshared.o add.o modify.o modrdn.o delete.o dl.o\
-	plugin_acl.o counters.o subentry.o object.o objset.o apibroker.o \
+	plugin_acl.o plugin_mmr.o counters.o subentry.o object.o objset.o apibroker.o \
 	csn.o csnset.o slapd_plhash.o attrlist.o vattr.o bitset.o rdn.o \
 	mapping_tree.o backend_manager.o task.o resourcelimit.o \
 	bulk_import.o security_wrappers.o index_subsystem.o sasl_map.o

+ 26 - 0
ldap/servers/slapd/pblock.c

@@ -2078,6 +2078,14 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value)
     case SLAPI_PLUGIN_ACL_MODS_UPDATE:
         (*(IFP *)value) = pblock->pb_plugin->plg_acl_mods_update;
         break;
+    /* MMR Plugin */
+    case SLAPI_PLUGIN_MMR_BETXN_PREOP:
+        (*(IFP *)value) = pblock->pb_plugin->plg_mmr_betxn_preop;
+	break;
+    case SLAPI_PLUGIN_MMR_BETXN_POSTOP:
+        (*(IFP *)value) = pblock->pb_plugin->plg_mmr_betxn_postop;
+	break;
+
     case SLAPI_REQUESTOR_DN:
         /* NOTE: It's not a copy of the DN */
         if (pblock->pb_op != NULL) {
@@ -2257,6 +2265,12 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value)
         }
         break;
 
+    case SLAPI_URP_TOMBSTONE_CONFLICT_DN:
+        if (pblock->pb_intop != NULL) {
+		(*(char **)value) = pblock->pb_intop->pb_urp_tombstone_conflict_dn;
+        }
+	break;
+		
     case SLAPI_SEARCH_CTRLS:
         if (pblock->pb_intop != NULL) {
             (*(LDAPControl ***)value) = pblock->pb_intop->pb_search_ctrls;
@@ -3806,6 +3820,14 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
     case SLAPI_PLUGIN_ACL_MODS_UPDATE:
         pblock->pb_plugin->plg_acl_mods_update = (IFP)value;
         break;
+    /* MMR Plugin */
+    case SLAPI_PLUGIN_MMR_BETXN_PREOP:
+	pblock->pb_plugin->plg_mmr_betxn_preop = (IFP) value;
+	break;
+    case SLAPI_PLUGIN_MMR_BETXN_POSTOP:
+	pblock->pb_plugin->plg_mmr_betxn_postop = (IFP) value;
+	break;
+
     case SLAPI_CLIENT_DNS:
         if (pblock->pb_conn == NULL) {
             slapi_log_err(SLAPI_LOG_ERR,
@@ -3919,6 +3941,10 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
         pblock->pb_intop->pb_urp_naming_collision_dn = (char *)value;
         break;
 
+    case SLAPI_URP_TOMBSTONE_CONFLICT_DN:
+	pblock->pb_intop->pb_urp_tombstone_conflict_dn = (char *)value;
+	break;
+
     case SLAPI_URP_TOMBSTONE_UNIQUEID:
         _pblock_assert_pb_intop(pblock);
         pblock->pb_intop->pb_urp_tombstone_uniqueid = (char *)value;

+ 1 - 0
ldap/servers/slapd/pblock_v3.h

@@ -141,6 +141,7 @@ typedef struct _slapi_pblock_intop
     char *pb_result_text;             /* result text when available */
     char *pb_urp_naming_collision_dn; /* replication naming conflict removal */
     char *pb_urp_tombstone_uniqueid;  /* replication change tombstone */
+    char * pb_urp_tombstone_conflict_dn; /* urp changed tombstone to conflict */
     int pb_opreturn;
     /* controls we know about */
     int pb_managedsait;

+ 5 - 0
ldap/servers/slapd/plugin.c

@@ -2261,6 +2261,9 @@ plugin_get_type_and_list(
     } else if (strcasecmp(plugintype, "accesscontrol") == 0) {
         *type = SLAPI_PLUGIN_ACL;
         plugin_list_index = PLUGIN_LIST_ACL;
+    } else if ( strcasecmp( plugintype, "mmr" ) == 0 ) {
+        *type = SLAPI_PLUGIN_MMR;
+        plugin_list_index = PLUGIN_LIST_MMR;
     } else if (strcasecmp(plugintype, "bepreoperation") == 0) {
         *type = SLAPI_PLUGIN_BEPREOPERATION;
         plugin_list_index = PLUGIN_LIST_BEPREOPERATION;
@@ -2337,6 +2340,8 @@ plugin_get_type_str(int type)
         return "syntax";
     } else if (type == SLAPI_PLUGIN_ACL) {
         return "accesscontrol";
+    } else if (type == SLAPI_PLUGIN_MMR){
+        return "mmr";
     } else if (type == SLAPI_PLUGIN_BEPREOPERATION) {
         return "bepreoperation";
     } else if (type == SLAPI_PLUGIN_BEPOSTOPERATION) {

+ 71 - 0
ldap/servers/slapd/plugin_mmr.c

@@ -0,0 +1,71 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2005 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * License: GPL (version 3 or any later version).
+ * See LICENSE for details. 
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+
+/*
+ * plugin_mmr.c - routines for calling mmr pre and postop plugins
+ */
+
+#include "slap.h"
+
+int
+plugin_call_mmr_plugin_preop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags)
+{
+	struct slapdplugin	*p;
+	int			rc = LDAP_INSUFFICIENT_ACCESS;
+	Operation	*operation;
+
+	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+	/* we don't perform acl check for internal operations  and if the plugin has set it not to be checked
+	if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
+		return LDAP_SUCCESS;
+	*/
+
+	/* call the global plugins first and then the backend specific */
+	for ( p = get_plugin_list(PLUGIN_LIST_MMR); p != NULL; p = p->plg_next ) {
+		if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_MMR_BETXN_PREOP, pb,
+									  (Slapi_DN*)slapi_entry_get_sdn_const (e))){
+			rc = (*p->plg_mmr_betxn_preop)(pb, flags);
+			if ( rc != LDAP_SUCCESS ) break;
+		}
+	}
+
+	return rc;
+}
+
+int
+plugin_call_mmr_plugin_postop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags)
+{
+	struct slapdplugin	*p;
+	int			rc = LDAP_INSUFFICIENT_ACCESS;
+	Operation	*operation;
+
+	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+	/* we don't perform acl check for internal operations  and if the plugin has set it not to be checked
+	if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
+		return LDAP_SUCCESS;
+	*/
+
+	/* call the global plugins first and then the backend specific */
+	for ( p = get_plugin_list(PLUGIN_LIST_MMR); p != NULL; p = p->plg_next ) {
+		if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_MMR_BETXN_POSTOP, pb,
+									  (Slapi_DN*)slapi_entry_get_sdn_const (e))){
+			rc = (*p->plg_mmr_betxn_postop)(pb, flags);
+			if ( rc != LDAP_SUCCESS ) break;
+		}
+	}
+
+	return rc;
+}

+ 6 - 0
ldap/servers/slapd/proto-slap.h

@@ -940,6 +940,12 @@ int plugin_call_acl_mods_access(Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods
 int plugin_call_acl_mods_update(Slapi_PBlock *pb, int optype);
 int plugin_call_acl_verify_syntax(Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf);
 
+/*
+ * plugin_mmr.c
+ */
+int plugin_call_mmr_plugin_preop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags);
+int plugin_call_mmr_plugin_postop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags);
+
 /*
  * pw_mgmt.c
  */

+ 10 - 1
ldap/servers/slapd/slap.h

@@ -860,7 +860,8 @@ struct matchingRuleList
 #define PLUGIN_LIST_INDEX                    19
 #define PLUGIN_LIST_BETXNPREOPERATION        20
 #define PLUGIN_LIST_BETXNPOSTOPERATION       21
-#define PLUGIN_LIST_GLOBAL_MAX               22
+#define PLUGIN_LIST_MMR                      22
+#define PLUGIN_LIST_GLOBAL_MAX               23
 
 /* plugin configuration attributes */
 #define ATTR_PLUGIN_PATH                   "nsslapd-pluginPath"
@@ -1282,6 +1283,14 @@ struct slapdplugin
 #define plg_acl_mods_allowed plg_un.plg_un_acl.plg_un_acl_mods_allowed
 #define plg_acl_mods_update plg_un.plg_un_acl.plg_un_acl_mods_update
 
+        struct plg_un_mmr_struct
+        {
+            IFP plg_un_mmr_betxn_preop;
+            IFP plg_un_mmr_betxn_postop;
+        } plg_un_mmr;
+#define plg_mmr_betxn_preop 		plg_un.plg_un_mmr.plg_un_mmr_betxn_preop
+#define plg_mmr_betxn_postop 		plg_un.plg_un_mmr.plg_un_mmr_betxn_postop
+
         /* password storage scheme (kexcoff) */
         struct plg_un_pwd_storage_scheme_struct
         {

+ 13 - 0
ldap/servers/slapd/slapi-plugin.h

@@ -6902,6 +6902,7 @@ slapi_timer_result slapi_timespec_expire_check(struct timespec *expire);
 #define SLAPI_PLUGIN_BETXNEXTENDEDOP          21
 #define SLAPI_PLUGIN_PREEXTOPERATION          22
 #define SLAPI_PLUGIN_POSTEXTOPERATION         23
+#define SLAPI_PLUGIN_MMR                      24
 
 /*
  * special return values for extended operation plugins (zero or positive
@@ -6920,6 +6921,13 @@ slapi_timer_result slapi_timespec_expire_check(struct timespec *expire);
                                  * Treat as SUCCESS, but skip the backend op.
                                  * Also, return SUCCESS to the client/supplier.
                                  * Necessary for the replication conflicts. */
+#define SLAPI_PLUGIN_NOOP_COMMIT -3 /* Special in be_pre_op/be_txn_pre_op.
+                                     * main op should be noop, but plugin made
+                                     * changes which need to be committed
+                                     */
+#define SLAPI_PLUGIN_NOOP_TOMBSTONE -4  /* Ignore the add and turn entry
+                                         * into tombstone
+                                         */
 
 /*
  * the following can be used as the second argument to the
@@ -6993,6 +7001,7 @@ slapi_timer_result slapi_timespec_expire_check(struct timespec *expire);
 /* urp flags */
 #define SLAPI_URP_NAMING_COLLISION_DN 286
 #define SLAPI_URP_TOMBSTONE_UNIQUEID  288
+#define SLAPI_URP_TOMBSTONE_CONFLICT_DN	293
 
 /* common to all plugins */
 #define SLAPI_PLUGIN              3
@@ -7192,6 +7201,10 @@ typedef struct slapi_plugindesc
 #define ACLPLUGIN_ACCESS_MODRDN               4
 #define ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS 5
 
+/* MMR plugin functions and arguments */
+#define SLAPI_PLUGIN_MMR_BETXN_PREOP		761
+#define SLAPI_PLUGIN_MMR_BETXN_POSTOP		762
+
 /* Authorization types */
 #define SLAPI_BE_MAXNESTLEVEL 742
 #define SLAPI_CLIENT_DNS 745

+ 2 - 0
ldap/servers/slapd/slapi-private.h

@@ -423,6 +423,8 @@ char *slapi_filter_to_string_internal(const struct slapi_filter *f, char *buf, s
 #define OP_FLAG_NEVER_CACHE 0x200000             /* never keep the entry in cache */
 #define OP_FLAG_TOMBSTONE_FIXUP 0x400000         /* operation is tombstone fixup op */
 #define OP_FLAG_BULK_IMPORT 0x800000             /* operation is bulk import */
+#define OP_FLAG_NOOP 0x01000000                  /* operation results from urp and
+                                                  * should be ignored */
 
 /* reverse search states */
 #define REV_STARTED 1

Some files were not shown because too many files changed in this diff