andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 4f722eff41b69dbfc17266ef6545c680b9f7c544 Mon Sep 17 00:00:00 2001
dc8c34
From: Rich Megginson <rmeggins@redhat.com>
dc8c34
Date: Tue, 9 Jul 2013 11:38:39 -0600
dc8c34
Subject: [PATCH 67/99] Ticket #47392 - ldbm errors when
dc8c34
 adding/modifying/deleting entries
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47392
dc8c34
Reviewed by: lkrispenz (Thanks!)
dc8c34
Branch: 389-ds-base-1.2.11
dc8c34
Fix Description: The problem is caused by cache consistency issues with the
dc8c34
RUV entry.  Before the txn starts, we grab a pointer to the RUV entry in
dc8c34
the cache.  When DNA (or any betxnpreop plugin) updates the database, it
dc8c34
will also grab a pointer to the cached RUV entry and modify it, out from
dc8c34
under the parent txn.  This can also cause the max CSN in the RUV to go
dc8c34
backwards - the nested txn will have a later CSN which will be
dc8c34
overwritten by the earlier CSN from the parent txn.
dc8c34
The fix is to move the ldbm_ruv_txn code inside the transaction loop after
dc8c34
the betxnpreop plugins have been run.  Also have to add modify_term inside
dc8c34
the retry logic to cancel the modify ruv txn stuff in order to retry.
dc8c34
The other part of the fix is to tell the code that updates the max CSN
dc8c34
in the RUV to skip changes that would cause the RUV to go backwards,
dc8c34
and return a code to the caller that tells the caller that the CSN is
dc8c34
already covered.  The code that updates the RUV for the txn will skip
dc8c34
the modify operations in that case.
dc8c34
Platforms tested: RHEL6 x86_64
dc8c34
Flag Day: no
dc8c34
Doc impact: no
dc8c34
(cherry picked from commit 9bf5ac83289dcadc922a628c652aebabc4725231)
dc8c34
(cherry picked from commit 42abece92028193530296b5d96a6cb5261d9aa61)
dc8c34
---
dc8c34
 ldap/servers/plugins/replication/repl5.h           |  4 +-
dc8c34
 ldap/servers/plugins/replication/repl5_plugins.c   | 29 ++++++--
dc8c34
 ldap/servers/plugins/replication/repl5_replica.c   | 84 ++++++++++++++++------
dc8c34
 .../plugins/replication/repl5_replica_config.c     |  4 +-
dc8c34
 ldap/servers/plugins/replication/repl5_ruv.c       | 55 ++++++++------
dc8c34
 ldap/servers/plugins/replication/repl5_ruv.h       |  1 +
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_add.c            | 31 ++++----
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_delete.c         | 32 +++++----
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modify.c         | 32 +++++----
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modrdn.c         | 31 ++++----
dc8c34
 ldap/servers/slapd/back-ldbm/misc.c                |  1 +
dc8c34
 11 files changed, 205 insertions(+), 99 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
dc8c34
index bd582bc..780b198 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5.h
dc8c34
+++ b/ldap/servers/plugins/replication/repl5.h
dc8c34
@@ -538,7 +538,7 @@ void   replica_replace_flags (Replica *r, PRUint32 flags);
dc8c34
 void replica_dump(Replica *r);
dc8c34
 void replica_set_enabled (Replica *r, PRBool enable);
dc8c34
 Object *replica_get_replica_from_dn (const Slapi_DN *dn);
dc8c34
-void replica_update_ruv(Replica *replica, const CSN *csn, const char *replica_purl);
dc8c34
+int replica_update_ruv(Replica *replica, const CSN *csn, const char *replica_purl);
dc8c34
 Object *replica_get_replica_for_op (Slapi_PBlock *pb);
dc8c34
 /* the functions below manipulate replica hash */
dc8c34
 int replica_init_name_hash ();
dc8c34
@@ -570,7 +570,7 @@ void replica_set_purge_delay (Replica *r, PRUint32 purge_delay);
dc8c34
 void replica_set_tombstone_reap_interval (Replica *r, long interval);
dc8c34
 void replica_update_ruv_consumer (Replica *r, RUV *supplier_ruv);
dc8c34
 void replica_set_ruv_dirty (Replica *r);
dc8c34
-void replica_write_ruv (Replica *r);
dc8c34
+int replica_write_ruv (Replica *r);
dc8c34
 char *replica_get_dn(Replica *r);
dc8c34
 void replica_check_for_tasks(Replica*r, Slapi_Entry *e);
dc8c34
 
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
dc8c34
index e3c3083..7aa2e2c 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_plugins.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
dc8c34
@@ -932,14 +932,15 @@ copy_operation_parameters(Slapi_PBlock *pb)
dc8c34
  * locally-processed update. This is called for both replicated
dc8c34
  * and non-replicated operations.
dc8c34
  */
dc8c34
-static void
dc8c34
+static int
dc8c34
 update_ruv_component(Replica *replica, CSN *opcsn, Slapi_PBlock *pb)
dc8c34
 {
dc8c34
     PRBool legacy;
dc8c34
     char *purl;
dc8c34
+    int rc = RUV_NOTFOUND;
dc8c34
 
dc8c34
 	if (!replica || !opcsn)
dc8c34
-		return;
dc8c34
+		return rc;
dc8c34
 
dc8c34
 	/* Replica configured, so update its ruv */
dc8c34
 	legacy = replica_is_legacy_consumer (replica);
dc8c34
@@ -948,12 +949,13 @@ update_ruv_component(Replica *replica, CSN *opcsn, Slapi_PBlock *pb)
dc8c34
 	else
dc8c34
 		purl = (char*)replica_get_purl_for_op (replica, pb, opcsn);
dc8c34
 
dc8c34
-	replica_update_ruv(replica, opcsn, purl);
dc8c34
+	rc = replica_update_ruv(replica, opcsn, purl);
dc8c34
 
dc8c34
 	if (legacy)
dc8c34
 	{
dc8c34
 		slapi_ch_free ((void**)&purl);
dc8c34
 	}
dc8c34
+	return rc;
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
@@ -1115,11 +1117,30 @@ write_changelog_and_ruv (Slapi_PBlock *pb)
dc8c34
 	  just read from the changelog in either the supplier or consumer ruv
dc8c34
 	*/
dc8c34
 	if (0 == return_value) {
dc8c34
+		char csn_str[CSN_STRSIZE];
dc8c34
 		CSN *opcsn;
dc8c34
+		int rc;
dc8c34
 
dc8c34
 		slapi_pblock_get( pb, SLAPI_OPERATION, &op );
dc8c34
 		opcsn = operation_get_csn(op);
dc8c34
-		update_ruv_component(r, opcsn, pb);
dc8c34
+		rc = update_ruv_component(r, opcsn, pb);
dc8c34
+		if (RUV_COVERS_CSN == rc) {
dc8c34
+        		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
dc8c34
+					"write_changelog_and_ruv: RUV already covers csn for "
dc8c34
+					"%s (uniqid: %s, optype: %lu) csn %s\n",
dc8c34
+					REPL_GET_DN(&op_params->target_address),
dc8c34
+					op_params->target_address.uniqueid,
dc8c34
+					op_params->operation_type,
dc8c34
+					csn_as_string(op_params->csn, PR_FALSE, csn_str));
dc8c34
+		} else if (rc != RUV_SUCCESS) {
dc8c34
+        		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+					"write_changelog_and_ruv: failed to update RUV for "
dc8c34
+					"%s (uniqid: %s, optype: %lu) to changelog csn %s\n",
dc8c34
+					REPL_GET_DN(&op_params->target_address),
dc8c34
+					op_params->target_address.uniqueid,
dc8c34
+					op_params->operation_type,
dc8c34
+					csn_as_string(op_params->csn, PR_FALSE, csn_str));
dc8c34
+		}
dc8c34
 	}
dc8c34
 
dc8c34
 	object_release (repl_obj);
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
dc8c34
index b3df831..8187be9 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_replica.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_replica.c
dc8c34
@@ -657,10 +657,11 @@ replica_set_ruv (Replica *r, RUV *ruv)
dc8c34
  * inbound replication session operation, and needs to update its
dc8c34
  * local RUV.
dc8c34
  */
dc8c34
-void
dc8c34
+int
dc8c34
 replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
dc8c34
 {
dc8c34
 	char csn_str[CSN_STRSIZE];
dc8c34
+	int rc = RUV_SUCCESS;
dc8c34
 	
dc8c34
 	PR_ASSERT(NULL != r);
dc8c34
 	PR_ASSERT(NULL != updated_csn);
dc8c34
@@ -673,11 +674,13 @@ replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
dc8c34
 	{
dc8c34
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: replica "
dc8c34
 			"is NULL\n");
dc8c34
+		rc = RUV_BAD_DATA;
dc8c34
 	}
dc8c34
 	else if (NULL == updated_csn)
dc8c34
 	{
dc8c34
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: csn "
dc8c34
 			"is NULL when updating replica %s\n", slapi_sdn_get_dn(r->repl_root));
dc8c34
+		rc = RUV_BAD_DATA;
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{
dc8c34
@@ -710,8 +713,17 @@ replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
dc8c34
 					}
dc8c34
 				}
dc8c34
 				/* Update max csn for local and remote replicas */
dc8c34
-				if (ruv_update_ruv (ruv, updated_csn, replica_purl, rid == r->repl_rid) 
dc8c34
-                    != RUV_SUCCESS)
dc8c34
+				rc = ruv_update_ruv (ruv, updated_csn, replica_purl, rid == r->repl_rid);
dc8c34
+				if (RUV_COVERS_CSN == rc)
dc8c34
+				{
dc8c34
+					slapi_log_error(SLAPI_LOG_REPL,
dc8c34
+						repl_plugin_name, "replica_update_ruv: RUV "
dc8c34
+						"for replica %s already covers max_csn = %s\n",
dc8c34
+						slapi_sdn_get_dn(r->repl_root),
dc8c34
+						csn_as_string(updated_csn, PR_FALSE, csn_str));
dc8c34
+					/* RUV is not dirty - no write needed */
dc8c34
+				}
dc8c34
+				else if (RUV_SUCCESS != rc)
dc8c34
 				{
dc8c34
 					slapi_log_error(SLAPI_LOG_FATAL,
dc8c34
 						repl_plugin_name, "replica_update_ruv: unable "
dc8c34
@@ -719,14 +731,18 @@ replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
dc8c34
 						slapi_sdn_get_dn(r->repl_root),
dc8c34
 						csn_as_string(updated_csn, PR_FALSE, csn_str));
dc8c34
 				}
dc8c34
-			
dc8c34
-				r->repl_ruv_dirty = PR_TRUE;
dc8c34
+				else
dc8c34
+				{
dc8c34
+					/* RUV updated - mark as dirty */
dc8c34
+					r->repl_ruv_dirty = PR_TRUE;
dc8c34
+				}
dc8c34
 			}
dc8c34
 			else
dc8c34
 			{
dc8c34
 				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
 					"replica_update_ruv: unable to get RUV object for replica "
dc8c34
 					"%s\n", slapi_sdn_get_dn(r->repl_root));
dc8c34
+				rc = RUV_NOTFOUND;
dc8c34
 			}
dc8c34
 		}
dc8c34
 		else
dc8c34
@@ -734,9 +750,11 @@ replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
dc8c34
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: "
dc8c34
 				"unable to initialize RUV for replica %s\n",
dc8c34
 				slapi_sdn_get_dn(r->repl_root));
dc8c34
+			rc = RUV_NOTFOUND;
dc8c34
 		}
dc8c34
 		PR_Unlock(r->repl_lock);
dc8c34
 	}
dc8c34
+	return rc;
dc8c34
 }
dc8c34
 
dc8c34
 /* 
dc8c34
@@ -2400,7 +2418,11 @@ _replica_update_state (time_t when, void *arg)
dc8c34
 	{
dc8c34
 		/* EY: the consumer needs to flush ruv to disk. */
dc8c34
 		PR_Unlock(r->repl_lock);
dc8c34
-		replica_write_ruv(r);
dc8c34
+		if (replica_write_ruv(r)) {
dc8c34
+			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
dc8c34
+				"_replica_update_state: failed write RUV for %s\n",
dc8c34
+				slapi_sdn_get_dn (r->repl_root));
dc8c34
+		}
dc8c34
 		goto done;
dc8c34
 	}
dc8c34
 	
dc8c34
@@ -2471,7 +2493,11 @@ _replica_update_state (time_t when, void *arg)
dc8c34
 	}
dc8c34
 
dc8c34
 	/* update RUV - performs its own locking */
dc8c34
-	replica_write_ruv (r);
dc8c34
+	if (replica_write_ruv(r)) {
dc8c34
+		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
dc8c34
+			"_replica_update_state: failed write RUV for %s\n",
dc8c34
+			slapi_sdn_get_dn (r->repl_root));
dc8c34
+	}
dc8c34
 
dc8c34
 	/* since this is the only place this value is changed and we are 
dc8c34
 	   guaranteed that only one thread enters the function, its ok
dc8c34
@@ -2487,10 +2513,10 @@ done:
dc8c34
 		object_release (replica_object);
dc8c34
 }
dc8c34
 
dc8c34
-void
dc8c34
+int
dc8c34
 replica_write_ruv (Replica *r)
dc8c34
 {	
dc8c34
-	int rc;
dc8c34
+	int rc = LDAP_SUCCESS;
dc8c34
 	Slapi_Mod smod;
dc8c34
 	Slapi_Mod smod_last_modified;
dc8c34
 	LDAPMod *mods [3];	 
dc8c34
@@ -2503,7 +2529,7 @@ replica_write_ruv (Replica *r)
dc8c34
     if (!r->repl_ruv_dirty)
dc8c34
     {
dc8c34
         PR_Unlock(r->repl_lock);
dc8c34
-        return;
dc8c34
+        return rc;
dc8c34
     }
dc8c34
 
dc8c34
 	PR_ASSERT (r->repl_ruv);
dc8c34
@@ -2560,6 +2586,8 @@ replica_write_ruv (Replica *r)
dc8c34
 	slapi_mod_done (&smod);
dc8c34
 	slapi_mod_done (&smod_last_modified);
dc8c34
 	slapi_pblock_destroy (pb);
dc8c34
+
dc8c34
+	return rc;
dc8c34
 }
dc8c34
 
dc8c34
 
dc8c34
@@ -2580,6 +2608,7 @@ replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods
dc8c34
     Slapi_Mod smod_last_modified;
dc8c34
     Slapi_Operation *op;
dc8c34
     Slapi_Entry *target_entry = NULL;
dc8c34
+    int rc = 0;
dc8c34
 
dc8c34
     slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &target_entry);
dc8c34
     if (target_entry && is_ruv_tombstone_entry(target_entry)) {
dc8c34
@@ -2618,19 +2647,32 @@ replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods
dc8c34
     object_release (ruv_obj);
dc8c34
     object_release (replica_obj);
dc8c34
 
dc8c34
-    ruv_set_max_csn( ruv_copy, opcsn, NULL );
dc8c34
-
dc8c34
-    ruv_to_smod( ruv_copy, &smod );
dc8c34
-    ruv_last_modified_to_smod( ruv_copy, &smod_last_modified );
dc8c34
+    rc = ruv_set_max_csn_ext( ruv_copy, opcsn, NULL, PR_TRUE );
dc8c34
+    if (rc == RUV_COVERS_CSN) { /* change would "revert" RUV - ignored */
dc8c34
+        rc = 0; /* tell caller to ignore */
dc8c34
+    } else if (rc == RUV_SUCCESS) {
dc8c34
+        rc = 1; /* tell caller success */
dc8c34
+    } else { /* error */
dc8c34
+        rc = -1; /* tell caller error */
dc8c34
+    }
dc8c34
 
dc8c34
+    if (rc == 1) {
dc8c34
+        ruv_to_smod( ruv_copy, &smod );
dc8c34
+        ruv_last_modified_to_smod( ruv_copy, &smod_last_modified );
dc8c34
+    }
dc8c34
     ruv_destroy( &ruv_copy );
dc8c34
 
dc8c34
-    *smods = slapi_mods_new();
dc8c34
-    slapi_mods_add_smod(*smods, &smod);
dc8c34
-    slapi_mods_add_smod(*smods, &smod_last_modified);
dc8c34
-    *uniqueid = slapi_ch_strdup( RUV_STORAGE_ENTRY_UNIQUEID );
dc8c34
+    if (rc == 1) {
dc8c34
+        *smods = slapi_mods_new();
dc8c34
+        slapi_mods_add_smod(*smods, &smod);
dc8c34
+        slapi_mods_add_smod(*smods, &smod_last_modified);
dc8c34
+        *uniqueid = slapi_ch_strdup( RUV_STORAGE_ENTRY_UNIQUEID );
dc8c34
+    } else {
dc8c34
+        *smods = NULL;
dc8c34
+        *uniqueid = NULL;
dc8c34
+    }
dc8c34
 
dc8c34
-    return (1);
dc8c34
+    return rc;
dc8c34
 }
dc8c34
 
dc8c34
 
dc8c34
@@ -3375,7 +3417,9 @@ replica_strip_cleaned_rids(Replica *r)
dc8c34
     while(rid[i] != 0){
dc8c34
         ruv_delete_replica(ruv, rid[i]);
dc8c34
         replica_set_ruv_dirty(r);
dc8c34
-        replica_write_ruv(r);
dc8c34
+        if (replica_write_ruv(r)) {
dc8c34
+		slapi_log_error (SLAPI_LOG_REPL, "replica_strip_cleaned_rids", "failed to write RUV\n");
dc8c34
+        }
dc8c34
         i++;
dc8c34
     }
dc8c34
     object_release(RUVObj);
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
dc8c34
index bbbe87e..7c625eb 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
dc8c34
@@ -1200,7 +1200,9 @@ replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not
dc8c34
 	}
dc8c34
 	rc = ruv_delete_replica(local_ruv, rid);
dc8c34
 	replica_set_ruv_dirty(replica);
dc8c34
-	replica_write_ruv(replica);
dc8c34
+	if (replica_write_ruv(replica)) {
dc8c34
+		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_task: could not write RUV\n");
dc8c34
+	}
dc8c34
 	object_release(RUVObj);
dc8c34
 
dc8c34
 	/* Update Mapping Tree to reflect RUV changes */
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
dc8c34
index 8fbd89c..2808c58 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_ruv.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
dc8c34
@@ -665,26 +665,34 @@ set_min_csn_nolock(RUV *ruv, const CSN *min_csn, const char *replica_purl)
dc8c34
 }
dc8c34
 
dc8c34
 static int
dc8c34
-set_max_csn_nolock(RUV *ruv, const CSN *max_csn, const char *replica_purl)
dc8c34
+set_max_csn_nolock_ext(RUV *ruv, const CSN *max_csn, const char *replica_purl, PRBool must_be_greater)
dc8c34
 {
dc8c34
-	int return_value;
dc8c34
+	int return_value = RUV_SUCCESS;
dc8c34
 	ReplicaId rid = csn_get_replicaid (max_csn);
dc8c34
 	RUVElement *replica = ruvGetReplica (ruv, rid);
dc8c34
-    if (NULL == replica)
dc8c34
-    {
dc8c34
-	    replica = ruvAddReplica (ruv, max_csn, replica_purl);
dc8c34
-        if (replica)
dc8c34
-            return_value = RUV_SUCCESS;
dc8c34
-        else
dc8c34
-            return_value = RUV_MEMORY_ERROR;
dc8c34
-	}
dc8c34
-	else
dc8c34
-	{
dc8c34
-        if (replica_purl && replica->replica_purl == NULL)
dc8c34
-            replica->replica_purl = slapi_ch_strdup (replica_purl);    
dc8c34
-		csn_free(&replica->csn);
dc8c34
-		replica->csn = csn_dup(max_csn);
dc8c34
-		replica->last_modified = current_time();
dc8c34
+	if (NULL == replica) {
dc8c34
+		replica = ruvAddReplica (ruv, max_csn, replica_purl);
dc8c34
+		if (replica)
dc8c34
+			return_value = RUV_SUCCESS;
dc8c34
+		else
dc8c34
+			return_value = RUV_MEMORY_ERROR;
dc8c34
+	} else {
dc8c34
+		if (replica_purl && replica->replica_purl == NULL)
dc8c34
+			replica->replica_purl = slapi_ch_strdup (replica_purl);
dc8c34
+		if (!must_be_greater || (csn_compare(replica->csn, max_csn) < 0)) {
dc8c34
+			csn_free(&replica->csn);
dc8c34
+			replica->csn = csn_dup(max_csn);
dc8c34
+			replica->last_modified = current_time();
dc8c34
+		} else {
dc8c34
+			char csn1[CSN_STRSIZE+1];
dc8c34
+			char csn2[CSN_STRSIZE+1];
dc8c34
+			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
dc8c34
+			                "set_max_csn_nolock_ext: new CSN [%s] for replica ID [%d] "
dc8c34
+			                "is less than the existing max CSN [%s] - ignoring\n",
dc8c34
+			                csn_as_string(max_csn, PR_FALSE, csn1), rid,
dc8c34
+			                csn_as_string(replica->csn, PR_FALSE, csn2));
dc8c34
+			return_value = RUV_COVERS_CSN;
dc8c34
+		}
dc8c34
 		return_value = RUV_SUCCESS;
dc8c34
 	}
dc8c34
 	return return_value;
dc8c34
@@ -704,9 +712,15 @@ ruv_set_min_csn(RUV *ruv, const CSN *min_csn, const char *replica_purl)
dc8c34
 int
dc8c34
 ruv_set_max_csn(RUV *ruv, const CSN *max_csn, const char *replica_purl)
dc8c34
 {
dc8c34
+	return ruv_set_max_csn_ext(ruv, max_csn, replica_purl, PR_FALSE);
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+ruv_set_max_csn_ext(RUV *ruv, const CSN *max_csn, const char *replica_purl, PRBool must_be_greater)
dc8c34
+{
dc8c34
 	int return_value;
dc8c34
 	slapi_rwlock_wrlock (ruv->lock);
dc8c34
-	return_value = set_max_csn_nolock(ruv, max_csn, replica_purl);
dc8c34
+	return_value = set_max_csn_nolock_ext(ruv, max_csn, replica_purl, must_be_greater);
dc8c34
 	slapi_rwlock_unlock (ruv->lock);
dc8c34
 	return return_value;
dc8c34
 }
dc8c34
@@ -1654,8 +1668,9 @@ int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool i
dc8c34
 		   * generated by this replica, we need to set the first_csn as the min csn in the
dc8c34
 		   * ruv */
dc8c34
 		  set_min_csn_nolock(ruv, first_csn, replica_purl);
dc8c34
-		} 
dc8c34
-		set_max_csn_nolock(ruv, max_csn, replica_purl);
dc8c34
+		}
dc8c34
+		/* only update the max_csn in the RUV if it is greater than the existing one */
dc8c34
+		rc = set_max_csn_nolock_ext(ruv, max_csn, replica_purl, PR_TRUE /* must be greater */);
dc8c34
 		/* It is possible that first_csn points to max_csn.
dc8c34
 		   We need to free it once */
dc8c34
 		if (max_csn != first_csn) {
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_ruv.h b/ldap/servers/plugins/replication/repl5_ruv.h
dc8c34
index 944f5ed..fdc8af2 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_ruv.h
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_ruv.h
dc8c34
@@ -108,6 +108,7 @@ int ruv_get_smallest_csn_for_replica(const RUV *ruv, ReplicaId rid, CSN **csn);
dc8c34
 int ruv_set_csns(RUV *ruv, const CSN *csn, const char *replica_purl);  
dc8c34
 int ruv_set_csns_keep_smallest(RUV *ruv, const CSN *csn);  
dc8c34
 int ruv_set_max_csn(RUV *ruv, const CSN *max_csn, const char *replica_purl);
dc8c34
+int ruv_set_max_csn_ext(RUV *ruv, const CSN *max_csn, const char *replica_purl, PRBool must_be_greater);
dc8c34
 int ruv_set_min_csn(RUV *ruv, const CSN *min_csn, const char *replica_purl);
dc8c34
 const char *ruv_get_purl_for_replica(const RUV *ruv, ReplicaId rid);
dc8c34
 char *ruv_get_replica_generation (const RUV *ruv);
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
index 78ca565..554822c 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
dc8c34
@@ -668,19 +668,6 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 		parententry = NULL;
dc8c34
 	}
dc8c34
 
dc8c34
-	if (!is_ruv && !is_fixup_operation) {
dc8c34
-		ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
-		if (-1 == ruv_c_init) {
dc8c34
-			LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
-				"ldbm_back_add: ldbm_txn_ruv_modify_context "
dc8c34
-				"failed to construct RUV modify context\n",
dc8c34
-				0, 0, 0);
dc8c34
-			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
-			retval = 0;
dc8c34
-			goto error_return;
dc8c34
-		}
dc8c34
-	}
dc8c34
-
dc8c34
 	if ( (originalentry = backentry_dup(addingentry )) == NULL ) {
dc8c34
 		ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
 		goto error_return;
dc8c34
@@ -718,6 +705,11 @@ ldbm_back_add( 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
 
dc8c34
 			/* We're re-trying */
dc8c34
 			LDAPDebug0Args(LDAP_DEBUG_BACKLDBM, "Add Retrying Transaction\n");
dc8c34
@@ -910,6 +902,19 @@ ldbm_back_add( Slapi_PBlock *pb )
dc8c34
 			}
dc8c34
 		}
dc8c34
 
dc8c34
+		if (!is_ruv && !is_fixup_operation) {
dc8c34
+			ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
+			if (-1 == ruv_c_init) {
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
+					"ldbm_back_add: ldbm_txn_ruv_modify_context "
dc8c34
+					"failed to construct RUV modify context\n",
dc8c34
+					0, 0, 0);
dc8c34
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+				retval = 0;
dc8c34
+				goto error_return;
dc8c34
+			}
dc8c34
+		}
dc8c34
+
dc8c34
 		if (ruv_c_init) {
dc8c34
 			retval = modify_update_all( be, pb, &ruv_c, &txn );
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
index d80c54e..3cf58f4 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
@@ -451,19 +451,6 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 		}
dc8c34
 	}
dc8c34
 
dc8c34
-	if (!is_ruv && !is_fixup_operation && !delete_tombstone_entry) {
dc8c34
-		ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
-		if (-1 == ruv_c_init) {
dc8c34
-			LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
-				"ldbm_back_delete: ldbm_txn_ruv_modify_context "
dc8c34
-				"failed to construct RUV modify context\n",
dc8c34
-				0, 0, 0);
dc8c34
-			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
-			retval = 0;
dc8c34
-			goto error_return;
dc8c34
-		}
dc8c34
-	}
dc8c34
-
dc8c34
 	/*
dc8c34
 	 * So, we believe that no code up till here actually added anything
dc8c34
 	 * to the persistent store. From now on, we're transacted
dc8c34
@@ -511,6 +498,12 @@ ldbm_back_delete( Slapi_PBlock *pb )
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
+				ruv_c_init = 0;
dc8c34
+			}
dc8c34
+
dc8c34
 			/* We're re-trying */
dc8c34
 			LDAPDebug0Args(LDAP_DEBUG_BACKLDBM,
dc8c34
 			               "Delete Retrying Transaction\n");
dc8c34
@@ -991,6 +984,19 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 			}
dc8c34
 		}
dc8c34
 
dc8c34
+		if (!is_ruv && !is_fixup_operation && !delete_tombstone_entry) {
dc8c34
+			ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
+			if (-1 == ruv_c_init) {
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
+					"ldbm_back_delete: ldbm_txn_ruv_modify_context "
dc8c34
+					"failed to construct RUV modify context\n",
dc8c34
+					0, 0, 0);
dc8c34
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+				retval = 0;
dc8c34
+				goto error_return;
dc8c34
+			}
dc8c34
+		}
dc8c34
+
dc8c34
 		if (ruv_c_init) {
dc8c34
 			retval = modify_update_all( be, pb, &ruv_c, &txn );
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
index 66b8ab8..32510ab 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
@@ -476,19 +476,6 @@ ldbm_back_modify( Slapi_PBlock *pb )
dc8c34
 		goto error_return;
dc8c34
 	}
dc8c34
 
dc8c34
-	if (!is_ruv && !is_fixup_operation) {
dc8c34
-		ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
-		if (-1 == ruv_c_init) {
dc8c34
-			LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
-				"ldbm_back_modify: ldbm_txn_ruv_modify_context "
dc8c34
-				"failed to construct RUV modify context\n",
dc8c34
-				0, 0, 0);
dc8c34
-			ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
-			retval = 0;
dc8c34
-			goto error_return;
dc8c34
-		}
dc8c34
-	}
dc8c34
-
dc8c34
 	/*
dc8c34
 	 * Grab a copy of the mods and the entry in case the be_txn_preop changes
dc8c34
 	 * the them.  If we have a failure, then we need to reset the mods to their
dc8c34
@@ -526,6 +513,12 @@ ldbm_back_modify( 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
+
dc8c34
 			LDAPDebug0Args(LDAP_DEBUG_BACKLDBM,
dc8c34
 			               "Modify Retrying Transaction\n");
dc8c34
 #ifndef LDBM_NO_BACKOFF_DELAY
dc8c34
@@ -638,6 +631,19 @@ ldbm_back_modify( Slapi_PBlock *pb )
dc8c34
 
dc8c34
 		}
dc8c34
 
dc8c34
+		if (!is_ruv && !is_fixup_operation) {
dc8c34
+			ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
+			if (-1 == ruv_c_init) {
dc8c34
+				LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
+					"ldbm_back_modify: ldbm_txn_ruv_modify_context "
dc8c34
+					"failed to construct RUV modify context\n",
dc8c34
+					0, 0, 0);
dc8c34
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
dc8c34
+				retval = 0;
dc8c34
+				goto error_return;
dc8c34
+			}
dc8c34
+		}
dc8c34
+
dc8c34
 		if (ruv_c_init) {
dc8c34
 			retval = modify_update_all( be, pb, &ruv_c, &txn );
dc8c34
 			if (DB_LOCK_DEADLOCK == retval) {
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
index 69fc053..b5cb90b 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
dc8c34
@@ -712,19 +712,6 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
         /* JCM - A subtree move could break ACIs, static groups, and dynamic groups. */
dc8c34
     }
dc8c34
 
dc8c34
-    if (!is_ruv && !is_fixup_operation) {
dc8c34
-        ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
-        if (-1 == ruv_c_init) {
dc8c34
-            LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
-                "ldbm_back_modrdn: ldbm_txn_ruv_modify_context "
dc8c34
-                "failed to construct RUV modify context\n",
dc8c34
-                0, 0, 0);
dc8c34
-            ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
-            retval = 0;
dc8c34
-            goto error_return;
dc8c34
-        }
dc8c34
-    }
dc8c34
-
dc8c34
     /*
dc8c34
      * make copies of the originals, no need to copy the mods because
dc8c34
      * we have already copied them
dc8c34
@@ -826,6 +813,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
             /* We're re-trying */
dc8c34
             LDAPDebug0Args(LDAP_DEBUG_BACKLDBM,
dc8c34
                            "Modrdn Retrying Transaction\n");
dc8c34
@@ -1028,6 +1020,19 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
dc8c34
             goto error_return;
dc8c34
         }
dc8c34
 
dc8c34
+        if (!is_ruv && !is_fixup_operation) {
dc8c34
+            ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
dc8c34
+            if (-1 == ruv_c_init) {
dc8c34
+                LDAPDebug( LDAP_DEBUG_ANY,
dc8c34
+                    "ldbm_back_modrdn: ldbm_txn_ruv_modify_context "
dc8c34
+                    "failed to construct RUV modify context\n",
dc8c34
+                    0, 0, 0);
dc8c34
+                ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
+                retval = 0;
dc8c34
+                goto error_return;
dc8c34
+            }
dc8c34
+        }
dc8c34
+
dc8c34
         if (ruv_c_init) {
dc8c34
             retval = modify_update_all( be, pb, &ruv_c, &txn );
dc8c34
             if (DB_LOCK_DEADLOCK == retval) {
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
index fd62df9..7a90742 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
@@ -420,6 +420,7 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
dc8c34
     /* Either something went wrong when the RUV callback tried to assemble
dc8c34
      * the updates for us, or there were no updates because the op doesn't
dc8c34
      * target a replica. */
dc8c34
+    /* or, the CSN is already covered by the RUV */
dc8c34
     if (1 != rc || NULL == smods || NULL == uniqueid) {
dc8c34
         return (rc);
dc8c34
     }
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34