andykimpe / rpms / 389-ds-base

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

Blame 0017-Ticket-337-improve-CLEANRUV-functionality.patch

dc8c34
From b04b2271f48f427330344ca9c61d76e312e9eb8c Mon Sep 17 00:00:00 2001
dc8c34
From: Mark Reynolds <mreynolds@redhat.com>
dc8c34
Date: Tue, 20 Nov 2012 16:14:42 -0500
dc8c34
Subject: [PATCH 17/22] Ticket 337 - improve CLEANRUV functionality
dc8c34
dc8c34
Bug Description:  Without anonymous access allowed, then task could not
dc8c34
                  contact other servers and retrieve data(ruv, maxcsns, etc).
dc8c34
dc8c34
Fix Description:  Changed all communication to use extended operations, and improved
dc8c34
                  sychronization between the replicas.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/337
dc8c34
dc8c34
Reviewed by: richm(Thanks Rich!)
dc8c34
(cherry picked from commit ecbd8b7513d05dab5876a88ca56b102c08a7a67c)
dc8c34
(cherry picked from commit 7a3014c0746134403f1fe9a25eac9581750aef0b)
dc8c34
---
dc8c34
 ldap/servers/plugins/replication/cl5_api.c         |   21 +-
dc8c34
 ldap/servers/plugins/replication/repl5.h           |   29 +-
dc8c34
 ldap/servers/plugins/replication/repl5_agmt.c      |   99 --
dc8c34
 ldap/servers/plugins/replication/repl5_agmtlist.c  |   11 +-
dc8c34
 .../servers/plugins/replication/repl5_connection.c |    6 +
dc8c34
 ldap/servers/plugins/replication/repl5_init.c      |   69 +-
dc8c34
 ldap/servers/plugins/replication/repl5_replica.c   |  132 +--
dc8c34
 .../plugins/replication/repl5_replica_config.c     | 1055 +++++++++++++-------
dc8c34
 ldap/servers/plugins/replication/repl_extop.c      |  266 ++++-
dc8c34
 ldap/servers/plugins/replication/replutil.c        |   47 +-
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_modify.c         |    7 +-
dc8c34
 ldap/servers/slapd/back-ldbm/misc.c                |    2 +-
dc8c34
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h     |    1 +
dc8c34
 ldap/servers/slapd/entry.c                         |   10 +-
dc8c34
 ldap/servers/slapd/slapi-private.h                 |    2 +-
dc8c34
 15 files changed, 1104 insertions(+), 653 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
dc8c34
index a347c57..6c94b3d 100644
dc8c34
--- a/ldap/servers/plugins/replication/cl5_api.c
dc8c34
+++ b/ldap/servers/plugins/replication/cl5_api.c
dc8c34
@@ -1474,13 +1474,13 @@ int cl5WriteOperation(const char *replName, const char *replGen,
dc8c34
 }
dc8c34
 
dc8c34
 /* Name:		cl5CreateReplayIterator
dc8c34
-   Description:	creates an iterator that allows to retireve changes that should
dc8c34
-				to be sent to the consumer identified by ruv. The iteration is peformed by 
dc8c34
+   Description:	creates an iterator that allows to retrieve changes that should
dc8c34
+				to be sent to the consumer identified by ruv. The iteration is performed by
dc8c34
                 repeated calls to cl5GetNextOperationToReplay.
dc8c34
    Parameters:  replica - replica whose data we wish to iterate;
dc8c34
 				ruv - consumer ruv;
dc8c34
 				iterator - iterator to be passed to cl5GetNextOperationToReplay call
dc8c34
-   Return:		CL5_SUCCESS, if function is successfull;
dc8c34
+   Return:		CL5_SUCCESS, if function is successful;
dc8c34
                 CL5_MISSING_DATA, if data that should be in the changelog is missing
dc8c34
                 CL5_PURGED_DATA, if some data that consumer needs has been purged.
dc8c34
                 Note that the iterator can be non null if the supplier contains
dc8c34
@@ -1488,14 +1488,14 @@ int cl5WriteOperation(const char *replName, const char *replGen,
dc8c34
                 CL5_NOTFOUND if the consumer is up to data with respect to the supplier
dc8c34
 				CL5_BAD_DATA if invalid parameter is passed;
dc8c34
 				CL5_BAD_STATE  if db has not been open;
dc8c34
-				CL5_DB_ERROR if any other db error occured;
dc8c34
+				CL5_DB_ERROR if any other db error occurred;
dc8c34
 				CL5_MEMORY_ERROR if memory allocation fails.
dc8c34
    Algorithm:   Build a list of csns from consumer's and supplier's ruv. For each element
dc8c34
                 of the consumer's ruv put max csn into the csn list. For each element
dc8c34
                 of the supplier's ruv not in the consumer's ruv put min csn from the
dc8c34
                 supplier's ruv into the list. The list contains, for each known replica,
dc8c34
                 the starting point for changes to be sent to the consumer.
dc8c34
-                Sort the list in accending order.
dc8c34
+                Sort the list in ascending order.
dc8c34
                 Build a hash which contains, for each known replica, whether the
dc8c34
                 supplier can bring the consumer up to data with respect to that replica.
dc8c34
                 The hash is used to decide whether a change can be sent to the consumer 
dc8c34
@@ -1503,7 +1503,7 @@ int cl5WriteOperation(const char *replName, const char *replGen,
dc8c34
                 we can bring the consumer up to date.
dc8c34
                 Position the db cursor on the change entry that corresponds to this csn.
dc8c34
                 Hash entries are created for each replica traversed so far. sendChanges
dc8c34
-                flag is set to FALSE for all repolicas except the last traversed.
dc8c34
+                flag is set to FALSE for all replicas except the last traversed.
dc8c34
                 
dc8c34
  */
dc8c34
 int cl5CreateReplayIteratorEx (Private_Repl_Protocol *prp, const RUV *consumerRuv, 
dc8c34
@@ -6543,7 +6543,9 @@ bail:
dc8c34
 void
dc8c34
 cl5CleanRUV(ReplicaId rid){
dc8c34
     CL5DBFile *file;
dc8c34
-    Object *obj;
dc8c34
+    Object *obj = NULL;
dc8c34
+
dc8c34
+    slapi_rwlock_wrlock (s_cl5Desc.stLock);
dc8c34
 
dc8c34
     obj = objset_first_obj(s_cl5Desc.dbFiles);
dc8c34
     while (obj){
dc8c34
@@ -6552,6 +6554,11 @@ cl5CleanRUV(ReplicaId rid){
dc8c34
         ruv_delete_replica(file->maxRUV, rid);
dc8c34
         obj = objset_next_obj(s_cl5Desc.dbFiles, obj);
dc8c34
     }
dc8c34
+    if(obj){
dc8c34
+        object_release (obj);
dc8c34
+    }
dc8c34
+
dc8c34
+    slapi_rwlock_unlock (s_cl5Desc.stLock);
dc8c34
 }
dc8c34
 
dc8c34
 void trigger_cl_trimming(ReplicaId rid){
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
dc8c34
index 61b51b0..bd582bc 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5.h
dc8c34
+++ b/ldap/servers/plugins/replication/repl5.h
dc8c34
@@ -97,8 +97,14 @@
dc8c34
 /* cleanallruv extended ops */
dc8c34
 #define REPL_CLEANRUV_OID "2.16.840.1.113730.3.6.5"
dc8c34
 #define REPL_ABORT_CLEANRUV_OID "2.16.840.1.113730.3.6.6"
dc8c34
-#define CLEANRUV_NOTIFIED 0
dc8c34
-#define CLEANRUV_RELEASED 1
dc8c34
+#define REPL_CLEANRUV_GET_MAXCSN_OID "2.16.840.1.113730.3.6.7"
dc8c34
+#define REPL_CLEANRUV_CHECK_STATUS_OID "2.16.840.1.113730.3.6.8"
dc8c34
+
dc8c34
+#define CLEANRUV_ACCEPTED "accepted"
dc8c34
+#define CLEANRUV_REJECTED "rejected"
dc8c34
+#define CLEANRUV_FINISHED "finished"
dc8c34
+#define CLEANRUV_CLEANING "cleaning"
dc8c34
+#define CLEANRUV_NO_MAXCSN "no maxcsn"
dc8c34
 
dc8c34
 /* DS 5.0 replication protocol error codes */
dc8c34
 #define NSDS50_REPL_REPLICA_READY 0x00 /* Replica ready, go ahead */
dc8c34
@@ -230,6 +236,8 @@ int multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb);
dc8c34
 int multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb);
dc8c34
 int multimaster_extop_cleanruv(Slapi_PBlock *pb);
dc8c34
 int multimaster_extop_abort_cleanruv(Slapi_PBlock *pb);
dc8c34
+int multimaster_extop_cleanruv_get_maxcsn(Slapi_PBlock *pb);
dc8c34
+int multimaster_extop_cleanruv_check_status(Slapi_PBlock *pb);
dc8c34
 int extop_noop(Slapi_PBlock *pb);
dc8c34
 struct berval *NSDS50StartReplicationRequest_new(const char *protocol_oid,
dc8c34
 	const char *repl_root, char **extra_referrals, CSN *csn);
dc8c34
@@ -365,9 +373,6 @@ PRBool agmt_is_enabled(Repl_Agmt *ra);
dc8c34
 int agmt_set_enabled_from_entry(Repl_Agmt *ra, Slapi_Entry *e, char *returntext);
dc8c34
 char **agmt_get_attrs_to_strip(Repl_Agmt *ra);
dc8c34
 int agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e);
dc8c34
-void agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e);
dc8c34
-int agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op);
dc8c34
-int agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid);
dc8c34
 int agmt_set_timeout(Repl_Agmt *ra, long timeout);
dc8c34
 void agmt_update_done(Repl_Agmt *ra, int is_total);
dc8c34
 
dc8c34
@@ -454,6 +459,7 @@ LDAP * conn_get_ldap(Repl_Connection *conn);
dc8c34
 void conn_lock(Repl_Connection *conn);
dc8c34
 void conn_unlock(Repl_Connection *conn);
dc8c34
 void conn_delete_internal_ext(Repl_Connection *conn);
dc8c34
+const char* conn_get_bindmethod(Repl_Connection *conn);
dc8c34
 
dc8c34
 /* In repl5_protocol.c */
dc8c34
 typedef struct repl_protocol Repl_Protocol;
dc8c34
@@ -608,7 +614,7 @@ int replica_config_init();
dc8c34
 void replica_config_destroy ();
dc8c34
 int get_replica_type(Replica *r);
dc8c34
 int replica_execute_cleanruv_task_ext(Object *r, ReplicaId rid);
dc8c34
-void add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn);
dc8c34
+void add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn, char *forcing);
dc8c34
 int is_cleaned_rid(ReplicaId rid);
dc8c34
 int replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
dc8c34
                                int *returncode, char *returntext, void *arg);
dc8c34
@@ -616,17 +622,15 @@ void replica_cleanallruv_thread_ext(void *arg);
dc8c34
 void stop_ruv_cleaning();
dc8c34
 int task_aborted();
dc8c34
 void replica_abort_task_thread(void *arg);
dc8c34
-void delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn);
dc8c34
+void remove_cleaned_rid(ReplicaId rid);
dc8c34
 int process_repl_agmts(Replica *replica, int *agmt_info, char *oid, Slapi_Task *task, struct berval *payload, int op);
dc8c34
 int decode_cleanruv_payload(struct berval *extop_value, char **payload);
dc8c34
-struct berval *create_ruv_payload(char *value);
dc8c34
-void replica_add_cleanruv_data(Replica *r, char *val);
dc8c34
-void replica_remove_cleanruv_data(Replica *r, char *val);
dc8c34
-CSN *replica_get_cleanruv_maxcsn(Replica *r, ReplicaId rid);
dc8c34
+struct berval *create_cleanruv_payload(char *value);
dc8c34
 void ruv_get_cleaned_rids(RUV *ruv, ReplicaId *rids);
dc8c34
 void add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root);
dc8c34
 int is_task_aborted(ReplicaId rid);
dc8c34
-void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root);
dc8c34
+void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root, int skip);
dc8c34
+int is_pre_cleaned_rid(ReplicaId rid);
dc8c34
 void set_cleaned_rid(ReplicaId rid);
dc8c34
 void cleanruv_log(Slapi_Task *task, char *task_type, char *fmt, ...);
dc8c34
 
dc8c34
@@ -643,6 +647,7 @@ typedef struct _cleanruv_data
dc8c34
 	char *repl_root;
dc8c34
 	Slapi_DN *sdn;
dc8c34
 	char *certify;
dc8c34
+	char *force;
dc8c34
 } cleanruv_data;
dc8c34
 
dc8c34
 /* replutil.c */
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
dc8c34
index d25f54b..935fb37 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_agmt.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
dc8c34
@@ -141,7 +141,6 @@ typedef struct repl5agmt {
dc8c34
 	char **attrs_to_strip; /* for fractional replication, if a "mod" is empty, strip out these attributes:
dc8c34
 	                        * modifiersname, modifytimestamp, internalModifiersname, internalModifyTimestamp, etc */
dc8c34
 	int agreement_type;
dc8c34
-	int cleanruv_notified[CLEANRIDSIZ + 1]; /* specifies if the replica has been notified of a CLEANALLRUV task */
dc8c34
 } repl5agmt;
dc8c34
 
dc8c34
 /* Forward declarations */
dc8c34
@@ -252,7 +251,6 @@ agmt_new_from_entry(Slapi_Entry *e)
dc8c34
 	Repl_Agmt *ra;
dc8c34
 	Slapi_Attr *sattr;
dc8c34
 	char *tmpstr;
dc8c34
-	char **clean_vals = NULL;
dc8c34
 	char **denied_attrs = NULL;
dc8c34
 	char *auto_initialize = NULL;
dc8c34
 	char *val_nsds5BeginReplicaRefresh = "start";
dc8c34
@@ -431,20 +429,6 @@ agmt_new_from_entry(Slapi_Entry *e)
dc8c34
 	ra->last_init_start_time = 0UL;
dc8c34
 	ra->last_init_status[0] = '\0';
dc8c34
 	
dc8c34
-	/* cleanruv notification */
dc8c34
-	clean_vals = slapi_entry_attr_get_charray(e, type_nsds5ReplicaCleanRUVnotified);
dc8c34
-	if(clean_vals){
dc8c34
-		int i;
dc8c34
-		for (i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
dc8c34
-			ra->cleanruv_notified[i] = atoi(clean_vals[i]);
dc8c34
-		}
dc8c34
-		if(i < CLEANRIDSIZ)
dc8c34
-		    ra->cleanruv_notified[i + 1] = 0;
dc8c34
-		slapi_ch_array_free(clean_vals);
dc8c34
-	} else {
dc8c34
-		ra->cleanruv_notified[0] = 0;
dc8c34
-	}
dc8c34
-
dc8c34
 	/* Fractional attributes */
dc8c34
 	slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeList, &sattr);
dc8c34
 
dc8c34
@@ -2623,89 +2607,6 @@ agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e)
dc8c34
     return -1;
dc8c34
 }
dc8c34
 
dc8c34
-int
dc8c34
-agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid){
dc8c34
-    int notified = 0;
dc8c34
-    int i;
dc8c34
-
dc8c34
-    PR_Lock(ra->lock);
dc8c34
-    for(i = 0; i < CLEANRIDSIZ && ra->cleanruv_notified[i]; i++){
dc8c34
-        if(ra->cleanruv_notified[i] == rid){
dc8c34
-            notified = 1;
dc8c34
-            break;
dc8c34
-        }
dc8c34
-    }
dc8c34
-    PR_Unlock(ra->lock);
dc8c34
-
dc8c34
-    return notified;
dc8c34
-}
dc8c34
-
dc8c34
-/*
dc8c34
- *  This will trigger agmt_set_cleanruv_notified_from_entry() to be called,
dc8c34
- *  which will update the in memory agmt.
dc8c34
- *
dc8c34
- *  op can be:  CLEANRUV_NOTIFIED or CLEANRUV_RELEASED
dc8c34
- */
dc8c34
-int
dc8c34
-agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op){
dc8c34
-    Slapi_PBlock *pb;
dc8c34
-    LDAPMod *mods[2];
dc8c34
-    LDAPMod mod;
dc8c34
-    struct berval *vals[2];
dc8c34
-    struct berval val;
dc8c34
-    char data[6];
dc8c34
-    int rc = 0;
dc8c34
-
dc8c34
-    if(ra == NULL){
dc8c34
-        return -1;
dc8c34
-    }
dc8c34
-
dc8c34
-    if(op == CLEANRUV_NOTIFIED){
dc8c34
-        /* add the cleanruv data */
dc8c34
-    	mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
dc8c34
-    } else {
dc8c34
-        /* remove the cleanruv data */
dc8c34
-    	mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
dc8c34
-    }
dc8c34
-
dc8c34
-    pb = slapi_pblock_new();
dc8c34
-    val.bv_len = PR_snprintf(data, sizeof(data), "%d", (int)rid);
dc8c34
-    mod.mod_type = (char *)type_nsds5ReplicaCleanRUVnotified;
dc8c34
-    mod.mod_bvalues = vals;
dc8c34
-    vals [0] = &val;
dc8c34
-    vals [1] = NULL;
dc8c34
-    val.bv_val = data;
dc8c34
-    mods[0] = &mod;
dc8c34
-    mods[1] = NULL;
dc8c34
-
dc8c34
-    slapi_modify_internal_set_pb_ext (pb, ra->dn, mods, NULL, NULL,
dc8c34
-        repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
-    slapi_modify_internal_pb (pb);
dc8c34
-    slapi_pblock_destroy(pb);
dc8c34
-
dc8c34
-    return rc;
dc8c34
-}
dc8c34
-
dc8c34
-void
dc8c34
-agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e){
dc8c34
-    char **attr_vals = NULL;
dc8c34
-    int i;
dc8c34
-
dc8c34
-    PR_Lock(ra->lock);
dc8c34
-    attr_vals = slapi_entry_attr_get_charray(e, type_nsds5ReplicaCleanRUVnotified);
dc8c34
-    if(attr_vals){
dc8c34
-        for (i = 0; i < CLEANRIDSIZ && attr_vals[i]; i++){
dc8c34
-            ra->cleanruv_notified[i] = atoi(attr_vals[i]);
dc8c34
-        }
dc8c34
-        if( i < CLEANRIDSIZ )
dc8c34
-            ra->cleanruv_notified[i + 1] = 0;
dc8c34
-        slapi_ch_array_free(attr_vals);
dc8c34
-    } else {
dc8c34
-        ra->cleanruv_notified[0] = 0;
dc8c34
-    }
dc8c34
-    PR_Unlock(ra->lock);
dc8c34
-}
dc8c34
-
dc8c34
 /* this is called whenever an update (total/incremental)
dc8c34
    is completed */
dc8c34
 void 
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
dc8c34
index 537cfd8..70f71a8 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
dc8c34
@@ -248,7 +248,12 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
dc8c34
             /* we don't allow delete attribute operations unless it was issued by
dc8c34
                the replication plugin - handled above */
dc8c34
             if (mods[i]->mod_op & LDAP_MOD_DELETE)
dc8c34
-            {                
dc8c34
+            {
dc8c34
+                if(strcasecmp (mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified) == 0){
dc8c34
+                    /* allow the deletion of cleanallruv agmt attr */
dc8c34
+                    continue;
dc8c34
+                }
dc8c34
+
dc8c34
                 slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " 
dc8c34
                                 "deletion of %s attribute is not allowed\n", type_nsds5ReplicaInitialize);	
dc8c34
                 *returncode = LDAP_UNWILLING_TO_PERFORM;
dc8c34
@@ -508,10 +513,6 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
dc8c34
                 rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
             }
dc8c34
         }
dc8c34
-        else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified))
dc8c34
-        {
dc8c34
-            agmt_set_cleanruv_notified_from_entry(agmt, e);
dc8c34
-        }
dc8c34
         else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
dc8c34
         {
dc8c34
             slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " 
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
dc8c34
index 51a2bc5..5efd0e6 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_connection.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_connection.c
dc8c34
@@ -1760,6 +1760,12 @@ bind_method_to_mech(int bindmethod)
dc8c34
 	return LDAP_SASL_SIMPLE;
dc8c34
 }
dc8c34
 
dc8c34
+const char*
dc8c34
+conn_get_bindmethod(Repl_Connection *conn)
dc8c34
+{
dc8c34
+    return (bind_method_to_mech(conn->bindmethod));
dc8c34
+}
dc8c34
+
dc8c34
 /*
dc8c34
  * Check the result of an ldap BIND operation to see we it
dc8c34
  * contains the expiration controls
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c
dc8c34
index 7a80c6f..a0f02fe 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_init.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_init.c
dc8c34
@@ -123,7 +123,7 @@ static char *cleanruv_oid_list[] = {
dc8c34
 		NULL
dc8c34
 };
dc8c34
 static char *cleanruv_name_list[] = {
dc8c34
-		NSDS_REPL_NAME_PREFIX " Cleanruv",
dc8c34
+		NSDS_REPL_NAME_PREFIX " CleanAllRUV",
dc8c34
 		NULL
dc8c34
 };
dc8c34
 static char *cleanruv_abort_oid_list[] = {
dc8c34
@@ -131,9 +131,26 @@ static char *cleanruv_abort_oid_list[] = {
dc8c34
 		NULL
dc8c34
 };
dc8c34
 static char *cleanruv_abort_name_list[] = {
dc8c34
-		NSDS_REPL_NAME_PREFIX " Cleanruv Abort",
dc8c34
+		NSDS_REPL_NAME_PREFIX " CleanAllRUV Abort",
dc8c34
 		NULL
dc8c34
 };
dc8c34
+static char *cleanruv_maxcsn_oid_list[] = {
dc8c34
+               REPL_CLEANRUV_GET_MAXCSN_OID,
dc8c34
+               NULL
dc8c34
+};
dc8c34
+static char *cleanruv_maxcsn_name_list[] = {
dc8c34
+               NSDS_REPL_NAME_PREFIX " CleanAllRUV Retrieve MaxCSN",
dc8c34
+               NULL
dc8c34
+};
dc8c34
+static char *cleanruv_status_oid_list[] = {
dc8c34
+               REPL_CLEANRUV_CHECK_STATUS_OID,
dc8c34
+               NULL
dc8c34
+};
dc8c34
+static char *cleanruv_status_name_list[] = {
dc8c34
+               NSDS_REPL_NAME_PREFIX " CleanAllRUV Check Status",
dc8c34
+               NULL
dc8c34
+};
dc8c34
+
dc8c34
 
dc8c34
 /* List of plugin identities for every plugin registered. Plugin identity
dc8c34
    is passed by the server in the plugin init function and must be supplied 
dc8c34
@@ -403,6 +420,52 @@ multimaster_end_extop_init( Slapi_PBlock *pb )
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
+int
dc8c34
+multimaster_cleanruv_maxcsn_extop_init( Slapi_PBlock *pb )
dc8c34
+{
dc8c34
+	int rc= 0; /* OK */
dc8c34
+	void *identity = NULL;
dc8c34
+
dc8c34
+	/* get plugin identity and store it to pass to internal operations */
dc8c34
+	slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
dc8c34
+	PR_ASSERT (identity);
dc8c34
+
dc8c34
+	if (slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)cleanruv_maxcsn_oid_list ) != 0  ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)cleanruv_maxcsn_name_list ) != 0  ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_cleanruv_get_maxcsn ))
dc8c34
+	{
dc8c34
+		slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_cleanruv_extop_init failed\n" );
dc8c34
+		rc= -1;
dc8c34
+	}
dc8c34
+
dc8c34
+	return rc;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+multimaster_cleanruv_status_extop_init( Slapi_PBlock *pb )
dc8c34
+{
dc8c34
+	int rc= 0; /* OK */
dc8c34
+	void *identity = NULL;
dc8c34
+
dc8c34
+	/* get plugin identity and store it to pass to internal operations */
dc8c34
+	slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
dc8c34
+	PR_ASSERT (identity);
dc8c34
+
dc8c34
+	if (slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)cleanruv_status_oid_list ) != 0  ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)cleanruv_status_name_list ) != 0  ||
dc8c34
+			  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_cleanruv_check_status ))
dc8c34
+	{
dc8c34
+		slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_cleanruv_extop_init failed\n" );
dc8c34
+		rc= -1;
dc8c34
+	}
dc8c34
+
dc8c34
+	return rc;
dc8c34
+}
dc8c34
+
dc8c34
 
dc8c34
 int
dc8c34
 multimaster_total_extop_init( Slapi_PBlock *pb )
dc8c34
@@ -679,6 +742,8 @@ int replication_multimaster_plugin_init(Slapi_PBlock *pb)
dc8c34
 		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_response_extop_init", multimaster_response_extop_init, "Multimaster replication extended response plugin", NULL, identity);
dc8c34
 		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_extop_init", multimaster_cleanruv_extop_init, "Multimaster replication cleanruv extended operation plugin", NULL, identity);
dc8c34
 		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_abort_extop_init", multimaster_cleanruv_abort_extop_init, "Multimaster replication cleanruv abort extended operation plugin", NULL, identity);
dc8c34
+		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_maxcsn_extop_init", multimaster_cleanruv_maxcsn_extop_init, "Multimaster replication cleanruv maxcsn extended operation plugin", NULL, identity);
dc8c34
+		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_status_extop_init", multimaster_cleanruv_status_extop_init, "Multimaster replication cleanruv status extended operation plugin", NULL, identity);
dc8c34
 		if (0 == rc)
dc8c34
 		{
dc8c34
 			multimaster_initialised = 1;
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
dc8c34
index 2b1d958..b3df831 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_replica.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_replica.c
dc8c34
@@ -88,7 +88,6 @@ struct replica {
dc8c34
 	PRBool state_update_inprogress; /* replica state is being updated */
dc8c34
 	PRLock *agmt_lock;          /* protects agreement creation, start and stop */
dc8c34
 	char *locking_purl;			/* supplier who has exclusive access */
dc8c34
-	char *repl_cleanruv_data[CLEANRIDSIZ + 1];
dc8c34
 };
dc8c34
 
dc8c34
 
dc8c34
@@ -310,7 +309,6 @@ replica_destroy(void **arg)
dc8c34
 {
dc8c34
 	Replica *r;
dc8c34
 	void *repl_name;
dc8c34
-	int i;
dc8c34
 
dc8c34
 	if (arg == NULL)
dc8c34
 		return;
dc8c34
@@ -397,10 +395,6 @@ replica_destroy(void **arg)
dc8c34
 		csnplFree(&r->min_csn_pl);;
dc8c34
 	}
dc8c34
 
dc8c34
-	for(i = 0;r->repl_cleanruv_data[i] != NULL; i++){
dc8c34
-		slapi_ch_free_string(&r->repl_cleanruv_data[i]);
dc8c34
-	}
dc8c34
-
dc8c34
 	slapi_ch_free((void **)arg);
dc8c34
 }
dc8c34
 
dc8c34
@@ -1502,7 +1496,7 @@ int replica_check_for_data_reload (Replica *r, void *arg)
dc8c34
                 slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
dc8c34
                     "Warning: for replica %s there were some differences between the changelog max RUV and the "
dc8c34
                     "database RUV.  If there are obsolete elements in the database RUV, you "
dc8c34
-                    "should remove them using CLEANRUV task.  If they are not obsolete, "
dc8c34
+                    "should remove them using the CLEANALLRUV task.  If they are not obsolete, "
dc8c34
                     "you should check their status to see why there are no changes from those "
dc8c34
                     "servers in the changelog.\n",
dc8c34
                     slapi_sdn_get_dn(r->repl_root));
dc8c34
@@ -1819,12 +1813,13 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
dc8c34
         PRThread *thread = NULL;
dc8c34
         struct berval *payload = NULL;
dc8c34
         CSN *maxcsn = NULL;
dc8c34
-        char *csnpart;
dc8c34
-        char *iter;
dc8c34
+        ReplicaId rid;
dc8c34
         char csnstr[CSN_STRSIZE];
dc8c34
-        char *ridstr;
dc8c34
         char *token = NULL;
dc8c34
-        ReplicaId rid;
dc8c34
+        char *forcing;
dc8c34
+        char *csnpart;
dc8c34
+        char *ridstr;
dc8c34
+        char *iter;
dc8c34
         int i;
dc8c34
 
dc8c34
         for(i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
dc8c34
@@ -1833,7 +1828,6 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
dc8c34
             /*
dc8c34
              *  Set the cleanruv data, and add the cleaned rid
dc8c34
              */
dc8c34
-            r->repl_cleanruv_data[i] = slapi_ch_strdup(clean_vals[i]);
dc8c34
             token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
dc8c34
             if(token){
dc8c34
                 rid = atoi(token);
dc8c34
@@ -1851,15 +1845,18 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
dc8c34
             maxcsn = csn_new();
dc8c34
             csn_init_by_string(maxcsn, csnpart);
dc8c34
             csn_as_string(maxcsn, PR_FALSE, csnstr);
dc8c34
-            add_cleaned_rid(rid, r, csnstr);
dc8c34
+            forcing = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
+            if(forcing == NULL){
dc8c34
+                forcing = "no";
dc8c34
+            }
dc8c34
 
dc8c34
             slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: cleanAllRUV task found, "
dc8c34
                 "resuming the cleaning of rid(%d)...\n", rid);
dc8c34
             /*
dc8c34
              *  Create payload
dc8c34
              */
dc8c34
-            ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr);
dc8c34
-            payload = create_ruv_payload(ridstr);
dc8c34
+            ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr, forcing);
dc8c34
+            payload = create_cleanruv_payload(ridstr);
dc8c34
             slapi_ch_free_string(&ridstr);
dc8c34
 
dc8c34
             if(payload == NULL){
dc8c34
@@ -1882,8 +1879,10 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
dc8c34
                 data->rid = rid;
dc8c34
                 data->task = NULL;
dc8c34
                 data->maxcsn = maxcsn;
dc8c34
-                data->sdn = slapi_sdn_dup(r->repl_root);
dc8c34
                 data->payload = payload;
dc8c34
+                data->sdn = slapi_sdn_dup(r->repl_root);
dc8c34
+                data->force = slapi_ch_strdup(forcing);
dc8c34
+                data->repl_root = NULL;
dc8c34
 
dc8c34
                 thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
dc8c34
                         (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
dc8c34
@@ -1895,11 +1894,11 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
dc8c34
                     csn_free(&maxcsn);
dc8c34
                     slapi_sdn_free(&data->sdn);
dc8c34
                     ber_bvfree(data->payload);
dc8c34
+                    slapi_ch_free_string(&data->force);
dc8c34
                     slapi_ch_free((void **)&data);
dc8c34
                 }
dc8c34
             }
dc8c34
         }
dc8c34
-        r->repl_cleanruv_data[i] = NULL;
dc8c34
 
dc8c34
 done:
dc8c34
         slapi_ch_array_free(clean_vals);
dc8c34
@@ -1909,13 +1908,12 @@ done:
dc8c34
     {
dc8c34
         PRThread *thread = NULL;
dc8c34
         struct berval *payload;
dc8c34
-        CSN *maxcsn = NULL;
dc8c34
-        char *iter;
dc8c34
+        ReplicaId rid;
dc8c34
+        char *certify = NULL;
dc8c34
         char *ridstr = NULL;
dc8c34
-        char *repl_root;
dc8c34
         char *token = NULL;
dc8c34
-        char *certify = NULL;
dc8c34
-        ReplicaId rid;
dc8c34
+        char *repl_root;
dc8c34
+        char *iter;
dc8c34
         int i;
dc8c34
 
dc8c34
         for(i = 0; clean_vals[i]; i++){
dc8c34
@@ -1926,21 +1924,27 @@ done:
dc8c34
                 rid = atoi(token);
dc8c34
                 if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
dc8c34
                     slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: invalid replica id(%d) "
dc8c34
-                        "aborting task.\n", rid);
dc8c34
+                        "aborting abort task.\n", rid);
dc8c34
                     goto done2;
dc8c34
                 }
dc8c34
             } else {
dc8c34
                 slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to parse cleanallruv "
dc8c34
-                    "data (%s), aborting task.\n",clean_vals[i]);
dc8c34
+                    "data (%s), aborting abort task.\n",clean_vals[i]);
dc8c34
                 goto done2;
dc8c34
             }
dc8c34
 
dc8c34
             repl_root = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
             certify = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
+
dc8c34
+            if(!is_cleaned_rid(rid)){
dc8c34
+                slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica id(%d) is not "
dc8c34
+                    "being cleaned, nothing to abort.  Aborting abort task.\n", rid);
dc8c34
+                delete_aborted_rid(r, rid, repl_root, 0);
dc8c34
+                goto done2;
dc8c34
+            }
dc8c34
+
dc8c34
+            add_aborted_rid(rid, r, repl_root);
dc8c34
             stop_ruv_cleaning();
dc8c34
-            maxcsn = replica_get_cleanruv_maxcsn(r, rid);
dc8c34
-            delete_cleaned_rid(r, rid, maxcsn);
dc8c34
-            csn_free(&maxcsn);
dc8c34
 
dc8c34
             slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: abort task found, "
dc8c34
                 "resuming abort of rid(%d).\n", rid);
dc8c34
@@ -1951,8 +1955,8 @@ done:
dc8c34
             if (data == NULL) {
dc8c34
                 slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to allocate cleanruv_data.\n");
dc8c34
             } else {
dc8c34
-                ridstr = slapi_ch_smprintf("%d:%s", rid, repl_root);
dc8c34
-                payload = create_ruv_payload(ridstr);
dc8c34
+                ridstr = slapi_ch_smprintf("%d:%s:%s", rid, repl_root, certify);
dc8c34
+                payload = create_cleanruv_payload(ridstr);
dc8c34
                 slapi_ch_free_string(&ridstr);
dc8c34
 
dc8c34
                 if(payload == NULL){
dc8c34
@@ -2583,7 +2587,7 @@ replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods
dc8c34
            must use the CLEANRUV task instead */
dc8c34
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
dc8c34
                         "replica_ruv_smods_for_op: attempted to directly modify the tombstone RUV "
dc8c34
-                        "entry [%s] - use the CLEANRUV task instead\n",
dc8c34
+                        "entry [%s] - use the CLEANALLRUV task instead\n",
dc8c34
                         slapi_entry_get_dn_const(target_entry));
dc8c34
         return (-1);
dc8c34
     }
dc8c34
@@ -3430,7 +3434,7 @@ replica_replace_ruv_tombstone(Replica *r)
dc8c34
 
dc8c34
     if (rc != LDAP_SUCCESS)
dc8c34
     {
dc8c34
-        if ((rc != LDAP_NO_SUCH_OBJECT) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
dc8c34
+        if ((rc != LDAP_NO_SUCH_OBJECT && rc != LDAP_TYPE_OR_VALUE_EXISTS) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
dc8c34
         {
dc8c34
             slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: "
dc8c34
                 "failed to update replication update vector for replica %s: LDAP "
dc8c34
@@ -3794,69 +3798,3 @@ replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value )
dc8c34
 
dc8c34
 	return rc;
dc8c34
 }
dc8c34
-
dc8c34
-void
dc8c34
-replica_add_cleanruv_data(Replica *r, char *val)
dc8c34
-{
dc8c34
-    int i;
dc8c34
-
dc8c34
-    PR_Lock(r->repl_lock);
dc8c34
-
dc8c34
-    for (i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] != NULL; i++); /* goto the end of the list */
dc8c34
-    if( i < CLEANRIDSIZ){
dc8c34
-        r->repl_cleanruv_data[i] = slapi_ch_strdup(val); /* append to list */
dc8c34
-        r->repl_cleanruv_data[i + 1] = 0;
dc8c34
-    }
dc8c34
-
dc8c34
-    PR_Unlock(r->repl_lock);
dc8c34
-}
dc8c34
-
dc8c34
-void
dc8c34
-replica_remove_cleanruv_data(Replica *r, char *val)
dc8c34
-{
dc8c34
-    int i;
dc8c34
-
dc8c34
-    PR_Lock(r->repl_lock);
dc8c34
-
dc8c34
-    for(i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] && strcmp(r->repl_cleanruv_data[i], val) != 0; i++);
dc8c34
-    if( i < CLEANRIDSIZ ){
dc8c34
-        slapi_ch_free_string(&r->repl_cleanruv_data[i]);
dc8c34
-        for(; i < CLEANRIDSIZ; i++){
dc8c34
-            /* rewrite entire array */
dc8c34
-            r->repl_cleanruv_data[i] = r->repl_cleanruv_data[i + 1];
dc8c34
-        }
dc8c34
-    }
dc8c34
-
dc8c34
-    PR_Unlock(r->repl_lock);
dc8c34
-}
dc8c34
-
dc8c34
-CSN *
dc8c34
-replica_get_cleanruv_maxcsn(Replica *r, ReplicaId rid)
dc8c34
-{
dc8c34
-    CSN *newcsn;
dc8c34
-    char *csnstr;
dc8c34
-    char *token;
dc8c34
-    char *iter;
dc8c34
-    int repl_rid = 0;
dc8c34
-    int i;
dc8c34
-
dc8c34
-    PR_Lock(r->repl_lock);
dc8c34
-
dc8c34
-    for(i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i]; i++){
dc8c34
-        token = ldap_utf8strtok_r(r->repl_cleanruv_data[i], ":", &iter);
dc8c34
-        if(token){
dc8c34
-            repl_rid = atoi(token);
dc8c34
-        }
dc8c34
-        csnstr = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
-        if(repl_rid == rid){
dc8c34
-            newcsn = csn_new();
dc8c34
-            csn_init_by_string(newcsn, csnstr);
dc8c34
-            PR_Unlock(r->repl_lock);
dc8c34
-            return newcsn;
dc8c34
-        }
dc8c34
-    }
dc8c34
-
dc8c34
-    PR_Unlock(r->repl_lock);
dc8c34
-
dc8c34
-    return NULL;
dc8c34
-}
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
dc8c34
index c5ca965..0fd785b 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
dc8c34
@@ -64,6 +64,7 @@
dc8c34
 
dc8c34
 int slapi_log_urp = SLAPI_LOG_REPL;
dc8c34
 static ReplicaId cleaned_rids[CLEANRIDSIZ + 1] = {0};
dc8c34
+static ReplicaId pre_cleaned_rids[CLEANRIDSIZ + 1] = {0};
dc8c34
 static ReplicaId aborted_rids[CLEANRIDSIZ + 1] = {0};
dc8c34
 static Slapi_RWLock *rid_lock = NULL;
dc8c34
 static Slapi_RWLock *abort_rid_lock = NULL;
dc8c34
@@ -84,20 +85,27 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
dc8c34
 static int replica_execute_cl2ldif_task (Object *r, char *returntext);
dc8c34
 static int replica_execute_ldif2cl_task (Object *r, char *returntext);
dc8c34
 static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
dc8c34
-static int replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext);
dc8c34
+static int replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, const char *force_cleaning, char *returntext);
dc8c34
 static void replica_cleanallruv_thread(void *arg);
dc8c34
-static void replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task);
dc8c34
+static void replica_send_cleanruv_task(Repl_Agmt *agmt, cleanruv_data *clean_data);
dc8c34
 static int check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task);
dc8c34
-static int check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task);
dc8c34
-static int replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result);
dc8c34
+static int check_agmts_are_caught_up(cleanruv_data *data, char *maxcsn);
dc8c34
+static int replica_cleanallruv_send_extop(Repl_Agmt *ra, cleanruv_data *data, int check_result);
dc8c34
 static int replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct berval *payload);
dc8c34
-static int replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task);
dc8c34
+static int replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *basedn, char *rid_text, char *maxcsn, Slapi_Task *task);
dc8c34
 static int replica_cleanallruv_replica_alive(Repl_Agmt *agmt);
dc8c34
-static int replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task);
dc8c34
+static int replica_cleanallruv_check_ruv(char *repl_root, Repl_Agmt *ra, char *rid_text, Slapi_Task *task);
dc8c34
 static int get_cleanruv_task_count();
dc8c34
 static int get_abort_cleanruv_task_count();
dc8c34
 static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
dc8c34
 static int replica_task_done(Replica *replica);
dc8c34
+static void delete_cleaned_rid_config(cleanruv_data *data);
dc8c34
+static int replica_cleanallruv_is_finished(Repl_Agmt *agmt, char *filter, Slapi_Task *task);
dc8c34
+static void check_replicas_are_done_cleaning(cleanruv_data *data);
dc8c34
+static void check_replicas_are_done_aborting(cleanruv_data *data );
dc8c34
+static CSN* replica_cleanallruv_find_maxcsn(Replica *replica, ReplicaId rid, char *basedn);
dc8c34
+static int replica_cleanallruv_get_replica_maxcsn(Repl_Agmt *agmt, char *rid_text, char *basedn, CSN **csn);
dc8c34
+static void preset_cleaned_rid(ReplicaId rid);
dc8c34
 static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
dc8c34
 
dc8c34
 /*
dc8c34
@@ -385,6 +393,12 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
dc8c34
                     if (apply_mods)
dc8c34
                         replica_set_legacy_consumer (r, PR_FALSE);
dc8c34
                 }
dc8c34
+                else if (strcasecmp (config_attr, type_replicaCleanRUV) == 0 ||
dc8c34
+                         strcasecmp (config_attr, type_replicaAbortCleanRUV) == 0)
dc8c34
+                {
dc8c34
+                    /* only allow the deletion of the cleanAllRUV config attributes */
dc8c34
+                    continue;
dc8c34
+                }
dc8c34
                 else
dc8c34
                 {
dc8c34
                     *returncode = LDAP_UNWILLING_TO_PERFORM;
dc8c34
@@ -891,7 +905,7 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
dc8c34
 		if (apply_mods)
dc8c34
 		{
dc8c34
 			Slapi_Task *empty_task = NULL;
dc8c34
-			return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext);
dc8c34
+			return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext, "no");
dc8c34
 		}
dc8c34
 		else
dc8c34
 			return LDAP_SUCCESS;
dc8c34
@@ -1225,35 +1239,52 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
dc8c34
     Slapi_Task *task = NULL;
dc8c34
     const Slapi_DN *task_dn;
dc8c34
     Slapi_DN *dn = NULL;
dc8c34
+    ReplicaId rid;
dc8c34
     Object *r;
dc8c34
+    const char *force_cleaning;
dc8c34
     const char *base_dn;
dc8c34
     const char *rid_str;
dc8c34
-    ReplicaId rid;
dc8c34
     int rc = SLAPI_DSE_CALLBACK_OK;
dc8c34
 
dc8c34
     /* allocate new task now */
dc8c34
     task = slapi_new_task(slapi_entry_get_ndn(e));
dc8c34
+    task_dn = slapi_entry_get_sdn(e);
dc8c34
     if(task == NULL){
dc8c34
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Failed to create new task\n");
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
         goto out;
dc8c34
     }
dc8c34
-
dc8c34
     /*
dc8c34
      *  Get our task settings
dc8c34
      */
dc8c34
     if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
dc8c34
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing replica-base-dn attribute");
dc8c34
+        cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
dc8c34
         *returncode = LDAP_OBJECT_CLASS_VIOLATION;
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
         goto out;
dc8c34
     }
dc8c34
     if ((rid_str = fetch_attr(e, "replica-id", 0)) == NULL){
dc8c34
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing replica-id attribute");
dc8c34
+        cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
dc8c34
         *returncode = LDAP_OBJECT_CLASS_VIOLATION;
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
         goto out;
dc8c34
     }
dc8c34
 
dc8c34
-    task_dn = slapi_entry_get_sdn(e);
dc8c34
+    if ((force_cleaning = fetch_attr(e, "replica-force-cleaning", 0)) != NULL){
dc8c34
+        if(strcasecmp(force_cleaning,"yes") != 0 && strcasecmp(force_cleaning,"no") != 0){
dc8c34
+            PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid value for replica-force-cleaning "
dc8c34
+                "(%s).  Value must be \"yes\" or \"no\" for task - (%s)",
dc8c34
+                force_cleaning, slapi_sdn_get_dn(task_dn));
dc8c34
+            cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
dc8c34
+            *returncode = LDAP_OPERATIONS_ERROR;
dc8c34
+            rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
+            goto out;
dc8c34
+        }
dc8c34
+    } else {
dc8c34
+        force_cleaning = "no";
dc8c34
+    }
dc8c34
     /*
dc8c34
      *  Check the rid
dc8c34
      */
dc8c34
@@ -1266,6 +1297,14 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
         goto out;
dc8c34
     }
dc8c34
+    if(is_cleaned_rid(rid)){
dc8c34
+         /* we are already cleaning this rid */
dc8c34
+         PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is already being cleaned", rid);
dc8c34
+         cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
dc8c34
+         *returncode = LDAP_UNWILLING_TO_PERFORM;
dc8c34
+         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
+         goto out;
dc8c34
+    }
dc8c34
     /*
dc8c34
      *  Get the replica object
dc8c34
      */
dc8c34
@@ -1279,7 +1318,7 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
dc8c34
     }
dc8c34
 
dc8c34
     /* clean the RUV's */
dc8c34
-    rc = replica_execute_cleanall_ruv_task (r, rid, task, returntext);
dc8c34
+    rc = replica_execute_cleanall_ruv_task (r, rid, task, force_cleaning, returntext);
dc8c34
 
dc8c34
 out:
dc8c34
     if(rc){
dc8c34
@@ -1302,31 +1341,36 @@ out:
dc8c34
  *
dc8c34
  */
dc8c34
 static int
dc8c34
-replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext)
dc8c34
+replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, const char* force_cleaning, char *returntext)
dc8c34
 {
dc8c34
-    PRThread *thread = NULL;
dc8c34
+    struct berval *payload = NULL;
dc8c34
     Slapi_Task *pre_task = NULL; /* this is supposed to be null for logging */
dc8c34
-    Replica *replica;
dc8c34
-    Object *ruv_obj;
dc8c34
     cleanruv_data *data = NULL;
dc8c34
+    PRThread *thread = NULL;
dc8c34
     CSN *maxcsn = NULL;
dc8c34
-    const RUV *ruv;
dc8c34
-    struct berval *payload = NULL;
dc8c34
-    char *ridstr = NULL;
dc8c34
+    Replica *replica;
dc8c34
     char csnstr[CSN_STRSIZE];
dc8c34
+    char *ridstr = NULL;
dc8c34
+    char *basedn = NULL;
dc8c34
     int rc = 0;
dc8c34
 
dc8c34
+    cleanruv_log(pre_task, CLEANALLRUV_ID,"Initiating CleanAllRUV Task...");
dc8c34
+
dc8c34
     if(get_cleanruv_task_count() >= CLEANRIDSIZ){
dc8c34
         /* we are already running the maximum number of tasks */
dc8c34
         cleanruv_log(pre_task, CLEANALLRUV_ID,
dc8c34
     	    "Exceeded maximum number of active CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
dc8c34
         return LDAP_UNWILLING_TO_PERFORM;
dc8c34
     }
dc8c34
-
dc8c34
     /*
dc8c34
      *  Grab the replica
dc8c34
      */
dc8c34
-    replica = (Replica*)object_get_data (r);
dc8c34
+    if(r){
dc8c34
+        replica = (Replica*)object_get_data (r);
dc8c34
+    } else {
dc8c34
+        cleanruv_log(pre_task, CLEANALLRUV_ID, "Replica object is NULL, aborting task");
dc8c34
+        return -1;
dc8c34
+    }
dc8c34
     /*
dc8c34
      *  Check if this is a consumer
dc8c34
      */
dc8c34
@@ -1342,32 +1386,25 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
dc8c34
     /*
dc8c34
      *  Grab the max csn of the deleted replica
dc8c34
      */
dc8c34
-    ruv_obj = replica_get_ruv(replica);
dc8c34
-    ruv = object_get_data (ruv_obj);
dc8c34
-    if(ruv_get_rid_max_csn(ruv, &maxcsn, rid) == RUV_BAD_DATA){
dc8c34
-        /* no maxcsn, can not proceed */
dc8c34
-        cleanruv_log(pre_task, CLEANALLRUV_ID, "Could not find maxcsn for rid (%d)", rid);
dc8c34
-        rc = -1;
dc8c34
-        object_release(ruv_obj);
dc8c34
-        goto fail;
dc8c34
-    } else {
dc8c34
-        object_release(ruv_obj);
dc8c34
-        if(maxcsn == NULL || csn_get_replicaid(maxcsn) == 0){
dc8c34
-            /*
dc8c34
-             *  This is for consistency with extop csn creation, where
dc8c34
-             *  we want the csn string to be "0000000000000000000" not ""
dc8c34
-             */
dc8c34
-            csn_free(&maxcsn);
dc8c34
-            maxcsn = csn_new();
dc8c34
-            csn_init_by_string(maxcsn, "");
dc8c34
-        }
dc8c34
-        csn_as_string(maxcsn, PR_FALSE, csnstr);
dc8c34
+    cleanruv_log(pre_task, CLEANALLRUV_ID, "Retrieving maxcsn...");
dc8c34
+    basedn = (char *)slapi_sdn_get_dn(replica_get_root(replica));
dc8c34
+    maxcsn = replica_cleanallruv_find_maxcsn(replica, rid, basedn);
dc8c34
+    if(maxcsn == NULL || csn_get_replicaid(maxcsn) == 0){
dc8c34
+        /*
dc8c34
+         *  This is for consistency with extop csn creation, where
dc8c34
+         *  we want the csn string to be "0000000000000000000" not ""
dc8c34
+         */
dc8c34
+        csn_free(&maxcsn);
dc8c34
+        maxcsn = csn_new();
dc8c34
+        csn_init_by_string(maxcsn, "");
dc8c34
     }
dc8c34
+    csn_as_string(maxcsn, PR_FALSE, csnstr);
dc8c34
+    cleanruv_log(pre_task, CLEANALLRUV_ID, "Found maxcsn (%s)",csnstr);
dc8c34
     /*
dc8c34
      *  Create payload
dc8c34
      */
dc8c34
-    ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)), csnstr);
dc8c34
-    payload = create_ruv_payload(ridstr);
dc8c34
+    ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, basedn, csnstr, force_cleaning);
dc8c34
+    payload = create_cleanruv_payload(ridstr);
dc8c34
     slapi_ch_free_string(&ridstr);
dc8c34
 
dc8c34
     if(payload == NULL){
dc8c34
@@ -1389,15 +1426,19 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
dc8c34
     data->replica = replica;
dc8c34
     data->rid = rid;
dc8c34
     data->task = task;
dc8c34
-    data->maxcsn = maxcsn;
dc8c34
     data->payload = payload;
dc8c34
     data->sdn = NULL;
dc8c34
+    data->maxcsn = maxcsn;
dc8c34
+    data->repl_root = slapi_ch_strdup(basedn);
dc8c34
+    data->force = slapi_ch_strdup(force_cleaning);
dc8c34
 
dc8c34
     thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread,
dc8c34
         (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
dc8c34
         PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
dc8c34
     if (thread == NULL) {
dc8c34
         rc = -1;
dc8c34
+        slapi_ch_free_string(&data->force);
dc8c34
+        slapi_ch_free_string(&data->repl_root);
dc8c34
         goto fail;
dc8c34
     } else {
dc8c34
         goto done;
dc8c34
@@ -1441,11 +1482,11 @@ replica_cleanallruv_thread_ext(void *arg)
dc8c34
 static void
dc8c34
 replica_cleanallruv_thread(void *arg)
dc8c34
 {
dc8c34
-    Object *ruv_obj = NULL;
dc8c34
+    cleanruv_data *data = arg;
dc8c34
     Object *agmt_obj = NULL;
dc8c34
+    Object *ruv_obj = NULL;
dc8c34
     Repl_Agmt *agmt = NULL;
dc8c34
     RUV *ruv = NULL;
dc8c34
-    cleanruv_data *data = arg;
dc8c34
     char csnstr[CSN_STRSIZE];
dc8c34
     char *returntext = NULL;
dc8c34
     char *rid_text = NULL;
dc8c34
@@ -1466,7 +1507,7 @@ replica_cleanallruv_thread(void *arg)
dc8c34
          * the backends might not be online yet.
dc8c34
          */
dc8c34
         PR_Lock( notify_lock );
dc8c34
-        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(5) );
dc8c34
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(10) );
dc8c34
         PR_Unlock( notify_lock );
dc8c34
         data->repl_obj = replica_get_replica_from_dn(data->sdn);
dc8c34
         if(data->repl_obj == NULL){
dc8c34
@@ -1488,17 +1529,25 @@ replica_cleanallruv_thread(void *arg)
dc8c34
     	aborted = 1;
dc8c34
     	goto done;
dc8c34
     }
dc8c34
+    if(data->repl_root == NULL){
dc8c34
+        /* we must have resumed from start up, fill in the repl root */
dc8c34
+        data->repl_root = slapi_ch_strdup(slapi_sdn_get_dn(replica_get_root(data->replica)));
dc8c34
+    }
dc8c34
     if(data->task){
dc8c34
         slapi_task_begin(data->task, 1);
dc8c34
     }
dc8c34
-    rid_text = slapi_ch_smprintf("{replica %d ldap", data->rid);
dc8c34
+    /*
dc8c34
+     *  Presetting the rid prevents duplicate thread creation, but allows the db and changelog to still
dc8c34
+     *  process updates from the rid.  set_cleaned_rid() blocks updates, so we don't want to do that... yet.
dc8c34
+     */
dc8c34
+    preset_cleaned_rid(data->rid);
dc8c34
+    rid_text = slapi_ch_smprintf("%d", data->rid);
dc8c34
     csn_as_string(data->maxcsn, PR_FALSE, csnstr);
dc8c34
-
dc8c34
     /*
dc8c34
      *  Add the cleanallruv task to the repl config - so we can handle restarts
dc8c34
      */
dc8c34
+    add_cleaned_rid(data->rid, data->replica, csnstr, data->force); /* marks config that we started cleaning a rid */
dc8c34
     cleanruv_log(data->task, CLEANALLRUV_ID, "Cleaning rid (%d)...", data->rid);
dc8c34
-    add_cleaned_rid(data->rid, data->replica, csnstr); /* marks config that we started cleaning a rid */
dc8c34
     /*
dc8c34
      *  First, wait for the maxcsn to be covered
dc8c34
      */
dc8c34
@@ -1506,7 +1555,7 @@ replica_cleanallruv_thread(void *arg)
dc8c34
     ruv_obj = replica_get_ruv(data->replica);
dc8c34
     ruv = object_get_data (ruv_obj);
dc8c34
     while(data->maxcsn && !is_task_aborted(data->rid) && !is_cleaned_rid(data->rid) && !slapi_is_shutting_down()){
dc8c34
-        if(csn_get_replicaid(data->maxcsn) == 0 || ruv_covers_csn_cleanallruv(ruv,data->maxcsn)){
dc8c34
+        if(csn_get_replicaid(data->maxcsn) == 0 || ruv_covers_csn_cleanallruv(ruv,data->maxcsn) || strcasecmp(data->force,"yes") == 0){
dc8c34
             /* We are caught up, now we can clean the ruv's */
dc8c34
             break;
dc8c34
         }
dc8c34
@@ -1517,6 +1566,8 @@ replica_cleanallruv_thread(void *arg)
dc8c34
     object_release(ruv_obj);
dc8c34
     /*
dc8c34
      *  Next, make sure all the replicas are up and running before sending off the clean ruv tasks
dc8c34
+     *
dc8c34
+     *  Even if we are forcing the cleaning, the replicas still need to be up
dc8c34
      */
dc8c34
     cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to be online...");
dc8c34
     if(check_agmts_are_alive(data->replica, data->rid, data->task)){
dc8c34
@@ -1528,7 +1579,7 @@ replica_cleanallruv_thread(void *arg)
dc8c34
      *  Make sure all the replicas have seen the max csn
dc8c34
      */
dc8c34
     cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to receive all the deleted replica updates...");
dc8c34
-    if(check_agmts_are_caught_up(data->replica, data->rid, csnstr, data->task)){
dc8c34
+    if(strcasecmp(data->force,"no") == 0 && check_agmts_are_caught_up(data, csnstr)){
dc8c34
         /* error, aborted or shutdown */
dc8c34
         aborted = 1;
dc8c34
         goto done;
dc8c34
@@ -1555,10 +1606,11 @@ replica_cleanallruv_thread(void *arg)
dc8c34
                 agmt_not_notified = 0;
dc8c34
                 continue;
dc8c34
             }
dc8c34
-            if(replica_cleanallruv_send_extop(agmt, data->rid, data->task, data->payload, 1) == 0){
dc8c34
+            if(replica_cleanallruv_send_extop(agmt, data, 1) == 0){
dc8c34
                 agmt_not_notified = 0;
dc8c34
             } else {
dc8c34
                 agmt_not_notified = 1;
dc8c34
+                cleanruv_log(data->task, CLEANALLRUV_ID, "Failed to send task to replica (%s)",agmt_get_long_name(agmt));
dc8c34
                 break;
dc8c34
             }
dc8c34
             agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
@@ -1609,10 +1661,11 @@ replica_cleanallruv_thread(void *arg)
dc8c34
                 found_dirty_rid = 0;
dc8c34
                 continue;
dc8c34
             }
dc8c34
-            if(replica_cleanallruv_check_ruv(agmt, rid_text, data->task) == 0){
dc8c34
+            if(replica_cleanallruv_check_ruv(data->repl_root, agmt, rid_text, data->task) == 0){
dc8c34
                 found_dirty_rid = 0;
dc8c34
             } else {
dc8c34
                 found_dirty_rid = 1;
dc8c34
+                cleanruv_log(data->task, CLEANALLRUV_ID,"Replica is not cleaned yet (%s)",agmt_get_long_name(agmt));
dc8c34
                 break;
dc8c34
             }
dc8c34
             agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
@@ -1623,7 +1676,7 @@ replica_cleanallruv_thread(void *arg)
dc8c34
             goto done;
dc8c34
         }
dc8c34
         if(found_dirty_rid == 0){
dc8c34
-           break;
dc8c34
+            break;
dc8c34
         }
dc8c34
         /*
dc8c34
          *  need to sleep between passes
dc8c34
@@ -1647,9 +1700,11 @@ done:
dc8c34
      */
dc8c34
     if(!aborted){
dc8c34
         trigger_cl_trimming(data->rid);
dc8c34
-        delete_cleaned_rid(data->replica, data->rid, data->maxcsn);
dc8c34
+        delete_cleaned_rid_config(data);
dc8c34
+        /* make sure all the replicas have been "pre_cleaned" before finishing */
dc8c34
+        check_replicas_are_done_cleaning(data);
dc8c34
         cleanruv_log(data->task, CLEANALLRUV_ID, "Successfully cleaned rid(%d).", data->rid);
dc8c34
-        slapi_task_finish(data->task, rc);
dc8c34
+        remove_cleaned_rid(data->rid);
dc8c34
     } else {
dc8c34
         /*
dc8c34
          *  Shutdown or abort
dc8c34
@@ -1658,29 +1713,189 @@ done:
dc8c34
             cleanruv_log(data->task, CLEANALLRUV_ID,"Server shutting down.  Process will resume at server startup");
dc8c34
         } else {
dc8c34
             cleanruv_log(data->task, CLEANALLRUV_ID,"Task aborted for rid(%d).",data->rid);
dc8c34
-        }
dc8c34
-        if(data->task){
dc8c34
-            slapi_task_finish(data->task, rc);
dc8c34
+            delete_cleaned_rid_config(data);
dc8c34
+            remove_cleaned_rid(data->rid);
dc8c34
         }
dc8c34
     }
dc8c34
-
dc8c34
+    if(data->task){
dc8c34
+        slapi_task_finish(data->task, rc);
dc8c34
+    }
dc8c34
     if(data->payload){
dc8c34
         ber_bvfree(data->payload);
dc8c34
     }
dc8c34
     if(data->repl_obj && free_obj){
dc8c34
         object_release(data->repl_obj);
dc8c34
     }
dc8c34
+    csn_free(&data->maxcsn);
dc8c34
     slapi_sdn_free(&data->sdn);
dc8c34
+    slapi_ch_free_string(&data->repl_root);
dc8c34
+    slapi_ch_free_string(&data->force);
dc8c34
     slapi_ch_free_string(&rid_text);
dc8c34
-    csn_free(&data->maxcsn);
dc8c34
     slapi_ch_free((void **)&data);
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
+ *  Loop over the agmts, and check if they are in the last phase of cleaning, meaning they have
dc8c34
+ *  released cleanallruv data from the config
dc8c34
+ */
dc8c34
+static void
dc8c34
+check_replicas_are_done_cleaning(cleanruv_data *data )
dc8c34
+{
dc8c34
+    Object *agmt_obj;
dc8c34
+    Repl_Agmt *agmt;
dc8c34
+    char csnstr[CSN_STRSIZE];
dc8c34
+    char *filter = NULL;
dc8c34
+    int not_all_cleaned = 1;
dc8c34
+    int interval = 10;
dc8c34
+
dc8c34
+    cleanruv_log(data->task, CLEANALLRUV_ID, "Waiting for all the replicas to finish cleaning...");
dc8c34
+
dc8c34
+    csn_as_string(data->maxcsn, PR_FALSE, csnstr);
dc8c34
+    filter = PR_smprintf("(%s=%d:%s:%s)", type_replicaCleanRUV,(int)data->rid, csnstr, data->force);
dc8c34
+    while(not_all_cleaned && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
dc8c34
+        agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
dc8c34
+        if(agmt_obj == NULL){
dc8c34
+            not_all_cleaned = 0;
dc8c34
+            break;
dc8c34
+        }
dc8c34
+        while (agmt_obj && !slapi_is_shutting_down()){
dc8c34
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
dc8c34
+            if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
dc8c34
+                agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
+                not_all_cleaned = 0;
dc8c34
+                continue;
dc8c34
+            }
dc8c34
+            if(replica_cleanallruv_is_finished(agmt, filter, data->task) == 0){
dc8c34
+                not_all_cleaned = 0;
dc8c34
+            } else {
dc8c34
+                not_all_cleaned = 1;
dc8c34
+                break;
dc8c34
+            }
dc8c34
+            agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
+        }
dc8c34
+        if(not_all_cleaned == 0 || is_task_aborted(data->rid) ){
dc8c34
+            break;
dc8c34
+        }
dc8c34
+        cleanruv_log(data->task, CLEANALLRUV_ID, "Not all replicas finished cleaning, retrying in %d seconds",interval);
dc8c34
+        PR_Lock( notify_lock );
dc8c34
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
dc8c34
+        PR_Unlock( notify_lock );
dc8c34
+        if(interval < 14400){ /* 4 hour max */
dc8c34
+            interval = interval * 2;
dc8c34
+        } else {
dc8c34
+            interval = 14400;
dc8c34
+        }
dc8c34
+    }
dc8c34
+    slapi_ch_free_string(&filter);
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Search this replica for the nsds5ReplicaCleanruv attribute, we don't return
dc8c34
+ *  an entry, we know it has finished cleaning.
dc8c34
+ */
dc8c34
+static int
dc8c34
+replica_cleanallruv_is_finished(Repl_Agmt *agmt, char *filter, Slapi_Task *task)
dc8c34
+{
dc8c34
+    Repl_Connection *conn = NULL;
dc8c34
+    ConnResult crc = 0;
dc8c34
+    struct berval *payload = NULL;
dc8c34
+    int msgid = 0;
dc8c34
+    int rc = -1;
dc8c34
+
dc8c34
+    if((conn = conn_new(agmt)) == NULL){
dc8c34
+        return -1;
dc8c34
+    }
dc8c34
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
+        payload = create_cleanruv_payload(filter);
dc8c34
+        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_CHECK_STATUS_OID, payload, NULL, &msgid);
dc8c34
+        if(crc == CONN_OPERATION_SUCCESS){
dc8c34
+            struct berval *retsdata = NULL;
dc8c34
+            char *retoid = NULL;
dc8c34
+
dc8c34
+            crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
dc8c34
+            if (CONN_OPERATION_SUCCESS == crc ){
dc8c34
+                char *response = NULL;
dc8c34
+
dc8c34
+                decode_cleanruv_payload(retsdata, &response);
dc8c34
+                if(response && strcmp(response,CLEANRUV_FINISHED) == 0){
dc8c34
+                    /* finished cleaning */
dc8c34
+                    rc = 0;
dc8c34
+                }
dc8c34
+                if (NULL != retsdata)
dc8c34
+                    ber_bvfree(retsdata);
dc8c34
+                slapi_ch_free_string(&response);
dc8c34
+                slapi_ch_free_string(&retoid);
dc8c34
+            }
dc8c34
+        }
dc8c34
+    } else {
dc8c34
+        rc = -1;
dc8c34
+    }
dc8c34
+    conn_delete_internal_ext(conn);
dc8c34
+    if(payload)
dc8c34
+    	ber_bvfree(payload);
dc8c34
+
dc8c34
+    return rc;
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Loop over the agmts, and check if they are in the last phase of aborting, meaning they have
dc8c34
+ *  released the abort cleanallruv data from the config
dc8c34
+ */
dc8c34
+static void
dc8c34
+check_replicas_are_done_aborting(cleanruv_data *data )
dc8c34
+{
dc8c34
+    Object *agmt_obj;
dc8c34
+    Repl_Agmt *agmt;
dc8c34
+    char *filter = NULL;
dc8c34
+    int not_all_aborted = 1;
dc8c34
+    int interval = 10;
dc8c34
+
dc8c34
+    cleanruv_log(data->task, ABORT_CLEANALLRUV_ID,"Waiting for all the replicas to finish aborting...");
dc8c34
+
dc8c34
+    filter = PR_smprintf("(%s=%d:%s)", type_replicaAbortCleanRUV, data->rid, data->repl_root);
dc8c34
+
dc8c34
+    while(not_all_aborted && !slapi_is_shutting_down()){
dc8c34
+        agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
dc8c34
+        if(agmt_obj == NULL){
dc8c34
+            not_all_aborted = 0;
dc8c34
+            break;
dc8c34
+        }
dc8c34
+        while (agmt_obj && !slapi_is_shutting_down()){
dc8c34
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
dc8c34
+            if(get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
dc8c34
+                agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
+                not_all_aborted = 0;
dc8c34
+                continue;
dc8c34
+            }
dc8c34
+            if(replica_cleanallruv_is_finished(agmt, filter, data->task) == 0){
dc8c34
+                not_all_aborted = 0;
dc8c34
+            } else {
dc8c34
+                not_all_aborted = 1;
dc8c34
+                break;
dc8c34
+            }
dc8c34
+            agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
+        }
dc8c34
+        if(not_all_aborted == 0){
dc8c34
+            break;
dc8c34
+        }
dc8c34
+        cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Not all replicas finished aborting, retrying in %d seconds",interval);
dc8c34
+        PR_Lock( notify_lock );
dc8c34
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
dc8c34
+        PR_Unlock( notify_lock );
dc8c34
+        if(interval < 14400){ /* 4 hour max */
dc8c34
+            interval = interval * 2;
dc8c34
+        } else {
dc8c34
+            interval = 14400;
dc8c34
+        }
dc8c34
+    }
dc8c34
+    slapi_ch_free_string(&filter);
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
  *  Waits for all the repl agmts to be have have the maxcsn.  Returns error only on abort or shutdown
dc8c34
  */
dc8c34
 static int
dc8c34
-check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task)
dc8c34
+check_agmts_are_caught_up(cleanruv_data *data, char *maxcsn)
dc8c34
 {
dc8c34
     Object *agmt_obj;
dc8c34
     Repl_Agmt *agmt;
dc8c34
@@ -1688,10 +1903,10 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
dc8c34
     int not_all_caughtup = 1;
dc8c34
     int interval = 10;
dc8c34
 
dc8c34
-    rid_text = slapi_ch_smprintf("{replica %d ldap", rid);
dc8c34
+    rid_text = slapi_ch_smprintf("%d", data->rid);
dc8c34
 
dc8c34
-    while(not_all_caughtup && !is_task_aborted(rid) && !slapi_is_shutting_down()){
dc8c34
-        agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
dc8c34
+    while(not_all_caughtup && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
dc8c34
+        agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
dc8c34
         if(agmt_obj == NULL){
dc8c34
             not_all_caughtup = 0;
dc8c34
             break;
dc8c34
@@ -1699,23 +1914,24 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
dc8c34
         while (agmt_obj){
dc8c34
             agmt = (Repl_Agmt*)object_get_data (agmt_obj);
dc8c34
             if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
dc8c34
-                agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
dc8c34
+                agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
                 not_all_caughtup = 0;
dc8c34
                 continue;
dc8c34
             }
dc8c34
-            if(replica_cleanallruv_check_maxcsn(agmt, rid_text, maxcsn, task) == 0){
dc8c34
+            if(replica_cleanallruv_check_maxcsn(agmt, data->repl_root, rid_text, maxcsn, data->task) == 0){
dc8c34
                 not_all_caughtup = 0;
dc8c34
             } else {
dc8c34
                 not_all_caughtup = 1;
dc8c34
+                cleanruv_log(data->task, CLEANALLRUV_ID, "Replica not caught up (%s)",agmt_get_long_name(agmt));
dc8c34
                 break;
dc8c34
             }
dc8c34
-            agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
dc8c34
-        } /* agmt while */
dc8c34
+            agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
dc8c34
+        }
dc8c34
 
dc8c34
-        if(not_all_caughtup == 0 || is_task_aborted(rid) ){
dc8c34
+        if(not_all_caughtup == 0 || is_task_aborted(data->rid) ){
dc8c34
             break;
dc8c34
         }
dc8c34
-        cleanruv_log(task, CLEANALLRUV_ID, "Not all replicas caught up, retrying in %d seconds",interval);
dc8c34
+        cleanruv_log(data->task, CLEANALLRUV_ID, "Not all replicas caught up, retrying in %d seconds",interval);
dc8c34
         PR_Lock( notify_lock );
dc8c34
         PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
dc8c34
         PR_Unlock( notify_lock );
dc8c34
@@ -1728,7 +1944,7 @@ check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_T
dc8c34
     }
dc8c34
     slapi_ch_free_string(&rid_text);
dc8c34
 
dc8c34
-    if(is_task_aborted(rid)){
dc8c34
+    if(is_task_aborted(data->rid)){
dc8c34
         return -1;
dc8c34
     }
dc8c34
 
dc8c34
@@ -1763,6 +1979,7 @@ check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
dc8c34
                 not_all_alive = 0;
dc8c34
             } else {
dc8c34
                 not_all_alive = 1;
dc8c34
+                cleanruv_log(task, CLEANALLRUV_ID, "Replica not online (%s)",agmt_get_long_name(agmt));
dc8c34
                 break;
dc8c34
             }
dc8c34
             agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
dc8c34
@@ -1793,7 +2010,7 @@ check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
dc8c34
  *  Create the CLEANALLRUV extended op payload
dc8c34
  */
dc8c34
 struct berval *
dc8c34
-create_ruv_payload(char *value)
dc8c34
+create_cleanruv_payload(char *value)
dc8c34
 {
dc8c34
     struct berval *req_data = NULL;
dc8c34
     BerElement *tmp_bere = NULL;
dc8c34
@@ -1801,10 +2018,7 @@ create_ruv_payload(char *value)
dc8c34
     if ((tmp_bere = der_alloc()) == NULL){
dc8c34
         goto error;
dc8c34
     }
dc8c34
-    if (ber_printf(tmp_bere, "{s", value) == -1){
dc8c34
-        goto error;
dc8c34
-    }
dc8c34
-    if (ber_printf(tmp_bere, "}") == -1){
dc8c34
+    if (ber_printf(tmp_bere, "{s}", value) == -1){
dc8c34
         goto error;
dc8c34
     }
dc8c34
     if (ber_flatten(tmp_bere, &req_data) == -1){
dc8c34
@@ -1832,7 +2046,7 @@ done:
dc8c34
  *  the CLEANALLRUV task.
dc8c34
  */
dc8c34
 static void
dc8c34
-replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
dc8c34
+replica_send_cleanruv_task(Repl_Agmt *agmt, cleanruv_data *clean_data)
dc8c34
 {
dc8c34
     Repl_Connection *conn;
dc8c34
     ConnResult crc = 0;
dc8c34
@@ -1859,7 +2073,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
dc8c34
         conn_delete_internal_ext(conn);
dc8c34
         return;
dc8c34
     }
dc8c34
-    val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", rid);
dc8c34
+    val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", clean_data->rid);
dc8c34
     sdn = agmt_get_replarea(agmt);
dc8c34
     mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
dc8c34
     mod.mod_type = "nsds5task";
dc8c34
@@ -1876,7 +2090,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
dc8c34
     rc = ldap_modify_ext_s( ld, repl_dn, mods, NULL, NULL);
dc8c34
 
dc8c34
     if(rc != LDAP_SUCCESS){
dc8c34
-    	cleanruv_log(task, CLEANALLRUV_ID, "Failed to add CLEANRUV task replica "
dc8c34
+    	cleanruv_log(clean_data->task, CLEANALLRUV_ID, "Failed to add CLEANRUV task replica "
dc8c34
             "(%s).  You will need to manually run the CLEANRUV task on this replica (%s) error (%d)",
dc8c34
             agmt_get_long_name(agmt), agmt_get_hostname(agmt), rc);
dc8c34
     }
dc8c34
@@ -1906,6 +2120,23 @@ is_cleaned_rid(ReplicaId rid)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
+is_pre_cleaned_rid(ReplicaId rid)
dc8c34
+{
dc8c34
+    int i;
dc8c34
+
dc8c34
+    slapi_rwlock_rdlock(rid_lock);
dc8c34
+    for(i = 0; i < CLEANRIDSIZ && pre_cleaned_rids[i] != 0; i++){
dc8c34
+        if(rid == pre_cleaned_rids[i]){
dc8c34
+            slapi_rwlock_unlock(rid_lock);
dc8c34
+            return 1;
dc8c34
+        }
dc8c34
+    }
dc8c34
+    slapi_rwlock_unlock(rid_lock);
dc8c34
+
dc8c34
+    return 0;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
 is_task_aborted(ReplicaId rid)
dc8c34
 {
dc8c34
 	int i;
dc8c34
@@ -1924,6 +2155,22 @@ is_task_aborted(ReplicaId rid)
dc8c34
     return 0;
dc8c34
 }
dc8c34
 
dc8c34
+static void
dc8c34
+preset_cleaned_rid(ReplicaId rid)
dc8c34
+{
dc8c34
+    int i;
dc8c34
+
dc8c34
+    slapi_rwlock_wrlock(rid_lock);
dc8c34
+    for(i = 0; i < CLEANRIDSIZ; i++){
dc8c34
+        if(pre_cleaned_rids[i] == 0){
dc8c34
+            pre_cleaned_rids[i] = rid;
dc8c34
+            pre_cleaned_rids[i + 1] = 0;
dc8c34
+            break;
dc8c34
+         }
dc8c34
+     }
dc8c34
+     slapi_rwlock_unlock(rid_lock);
dc8c34
+}
dc8c34
+
dc8c34
 /*
dc8c34
  *  Just add the rid to the in memory, as we don't want it to survive after a restart,
dc8c34
  *  This prevent the changelog from sending updates from this rid, and the local ruv
dc8c34
@@ -1948,7 +2195,7 @@ set_cleaned_rid(ReplicaId rid)
dc8c34
  *  Add the rid and maxcsn to the repl config (so we can resume after a server restart)
dc8c34
  */
dc8c34
 void
dc8c34
-add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
dc8c34
+add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn, char *forcing)
dc8c34
 {
dc8c34
     Slapi_PBlock *pb;
dc8c34
     struct berval *vals[2];
dc8c34
@@ -1965,7 +2212,7 @@ add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
dc8c34
     /*
dc8c34
      *  Write the rid & maxcsn to the config entry
dc8c34
      */
dc8c34
-    val.bv_len = PR_snprintf(data, sizeof(data),"%d:%s", rid, maxcsn);
dc8c34
+    val.bv_len = PR_snprintf(data, sizeof(data),"%d:%s:%s", rid, maxcsn, forcing);
dc8c34
     dn = replica_get_dn(r);
dc8c34
     pb = slapi_pblock_new();
dc8c34
     mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
dc8c34
@@ -1977,13 +2224,11 @@ add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
dc8c34
     mods[0] = &mod;
dc8c34
     mods[1] = NULL;
dc8c34
 
dc8c34
-    replica_add_cleanruv_data(r, val.bv_val);
dc8c34
-
dc8c34
     slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
dc8c34
         repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
     slapi_modify_internal_pb (pb);
dc8c34
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
dc8c34
-    if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS){
dc8c34
+    if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_OBJECT){
dc8c34
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to update replica "
dc8c34
             "config (%d), rid (%d)\n", rc, rid);
dc8c34
     }
dc8c34
@@ -2036,7 +2281,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
dc8c34
         repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
     slapi_modify_internal_pb (pb);
dc8c34
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
dc8c34
-    if (rc != LDAP_SUCCESS){
dc8c34
+    if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS && rc != LDAP_NO_SUCH_OBJECT){
dc8c34
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to update "
dc8c34
         "replica config (%d), rid (%d)\n", rc, rid);
dc8c34
     }
dc8c34
@@ -2047,7 +2292,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
dc8c34
 }
dc8c34
 
dc8c34
 void
dc8c34
-delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
dc8c34
+delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root, int skip){
dc8c34
     Slapi_PBlock *pb;
dc8c34
     LDAPMod *mods[2];
dc8c34
     LDAPMod mod;
dc8c34
@@ -2061,117 +2306,126 @@ delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
dc8c34
     if(r == NULL)
dc8c34
         return;
dc8c34
 
dc8c34
-    /*
dc8c34
-     *  Remove this rid, and optimize the array
dc8c34
-     */
dc8c34
-    slapi_rwlock_wrlock(abort_rid_lock);
dc8c34
-    for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != rid; i++); /* found rid, stop */
dc8c34
-    for(; i < CLEANRIDSIZ; i++){
dc8c34
-        /* rewrite entire array */
dc8c34
-        aborted_rids[i] = aborted_rids[i + 1];
dc8c34
+    if(skip){
dc8c34
+        /* skip the deleting of the config, and just remove the in memory rid */
dc8c34
+        slapi_rwlock_wrlock(abort_rid_lock);
dc8c34
+        for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != rid; i++); /* found rid, stop */
dc8c34
+        for(; i < CLEANRIDSIZ; i++){
dc8c34
+            /* rewrite entire array */
dc8c34
+            aborted_rids[i] = aborted_rids[i + 1];
dc8c34
+        }
dc8c34
+        slapi_rwlock_unlock(abort_rid_lock);
dc8c34
+    } else {
dc8c34
+        /* only remove the config, leave the in-memory rid */
dc8c34
+        dn = replica_get_dn(r);
dc8c34
+        pb = slapi_pblock_new();
dc8c34
+        data = PR_smprintf("%d:%s", (int)rid, repl_root);
dc8c34
+
dc8c34
+        mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
dc8c34
+        mod.mod_type = (char *)type_replicaAbortCleanRUV;
dc8c34
+        mod.mod_bvalues = vals;
dc8c34
+        vals [0] = &val;
dc8c34
+        vals [1] = NULL;
dc8c34
+        val.bv_val = data;
dc8c34
+        val.bv_len = strlen (data);
dc8c34
+        mods[0] = &mod;
dc8c34
+        mods[1] = NULL;
dc8c34
+
dc8c34
+        slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
+        slapi_modify_internal_pb (pb);
dc8c34
+        slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
dc8c34
+        if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT){
dc8c34
+             slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
dc8c34
+             "config (%d), rid (%d)\n", rc, rid);
dc8c34
+        }
dc8c34
+        slapi_pblock_destroy (pb);
dc8c34
+        slapi_ch_free_string(&dn;;
dc8c34
+        slapi_ch_free_string(&data);
dc8c34
     }
dc8c34
-    slapi_rwlock_unlock(abort_rid_lock);
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Just remove the dse.ldif config, but we need to keep the cleaned rids in memory until we know we are done
dc8c34
+ */
dc8c34
+static void
dc8c34
+delete_cleaned_rid_config(cleanruv_data *clean_data)
dc8c34
+{
dc8c34
+    Slapi_PBlock *pb;
dc8c34
+    LDAPMod *mods[2];
dc8c34
+    LDAPMod mod;
dc8c34
+    struct berval *vals[2];
dc8c34
+    struct berval val;
dc8c34
+    char data[CSN_STRSIZE + 15];
dc8c34
+    char csnstr[CSN_STRSIZE];
dc8c34
+    char *dn;
dc8c34
+    int rc;
dc8c34
+
dc8c34
     /*
dc8c34
      *  Prepare the mods for the config entry
dc8c34
      */
dc8c34
-    dn = replica_get_dn(r);
dc8c34
+    csn_as_string(clean_data->maxcsn, PR_FALSE, csnstr);
dc8c34
+    val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s:%s", (int)clean_data->rid, csnstr, clean_data->force);
dc8c34
+    dn = replica_get_dn(clean_data->replica);
dc8c34
     pb = slapi_pblock_new();
dc8c34
-    data = PR_smprintf("%d:%s", (int)rid, repl_root);
dc8c34
-
dc8c34
     mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
dc8c34
     mod.mod_type = (char *)type_replicaAbortCleanRUV;
dc8c34
+    mod.mod_type = (char *)type_replicaCleanRUV;
dc8c34
     mod.mod_bvalues = vals;
dc8c34
     vals [0] = &val;
dc8c34
     vals [1] = NULL;
dc8c34
     val.bv_val = data;
dc8c34
-    val.bv_len = strlen (data);
dc8c34
+
dc8c34
     mods[0] = &mod;
dc8c34
     mods[1] = NULL;
dc8c34
-
dc8c34
     slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
     slapi_modify_internal_pb (pb);
dc8c34
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
dc8c34
     if (rc != LDAP_SUCCESS){
dc8c34
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
dc8c34
-            "config (%d), rid (%d)\n", rc, rid);
dc8c34
-    }
dc8c34
-    slapi_pblock_destroy (pb);
dc8c34
-    slapi_ch_free_string(&dn;;
dc8c34
-    slapi_ch_free_string(&data);
dc8c34
-}
dc8c34
+        /*
dc8c34
+         *  When aborting a task, we don't know if the "force" option was used.
dc8c34
+         *  So we assume it is set to "no", but if this op fails, we'll try "yes"
dc8c34
+         */
dc8c34
+        slapi_pblock_destroy (pb);
dc8c34
+        pb = slapi_pblock_new();
dc8c34
+        memset(data,'0',sizeof(data));
dc8c34
+        val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s:yes", (int)clean_data->rid, csnstr);
dc8c34
+        slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
+        slapi_modify_internal_pb (pb);
dc8c34
+        slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
dc8c34
+        if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT){
dc8c34
+            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to remove replica config "
dc8c34
+                "(%d), rid (%d)\n", rc, clean_data->rid);
dc8c34
+        }
dc8c34
+     }
dc8c34
+     slapi_pblock_destroy (pb);
dc8c34
+     slapi_ch_free_string(&dn;;
dc8c34
+ }
dc8c34
 
dc8c34
 /*
dc8c34
  *  Remove the rid from our list, and the config
dc8c34
  */
dc8c34
 void
dc8c34
-delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn)
dc8c34
+remove_cleaned_rid(ReplicaId rid)
dc8c34
 {
dc8c34
-    Slapi_PBlock *pb;
dc8c34
-    Object *agmt_obj;
dc8c34
-    Repl_Agmt *agmt;
dc8c34
-    LDAPMod *mods[2];
dc8c34
-    LDAPMod mod;
dc8c34
-    struct berval *vals[2];
dc8c34
-    struct berval val;
dc8c34
-    char *dn;
dc8c34
-    char data[CSN_STRSIZE + 10];
dc8c34
-    char csnstr[CSN_STRSIZE];
dc8c34
-    int rc;
dc8c34
     int i;
dc8c34
-
dc8c34
-    if(r == NULL || maxcsn == NULL)
dc8c34
-        return;
dc8c34
-
dc8c34
     /*
dc8c34
      *  Remove this rid, and optimize the array
dc8c34
      */
dc8c34
     slapi_rwlock_wrlock(rid_lock);
dc8c34
+
dc8c34
     for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != rid; i++); /* found rid, stop */
dc8c34
     for(; i < CLEANRIDSIZ; i++){
dc8c34
         /* rewrite entire array */
dc8c34
         cleaned_rids[i] = cleaned_rids[i + 1];
dc8c34
     }
dc8c34
-    slapi_rwlock_unlock(rid_lock);
dc8c34
-    /*
dc8c34
-     *  Prepare the mods for the config entry
dc8c34
-     */
dc8c34
-    csn_as_string(maxcsn, PR_FALSE, csnstr);
dc8c34
-    val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s", (int)rid, csnstr);
dc8c34
-    dn = replica_get_dn(r);
dc8c34
-    pb = slapi_pblock_new();
dc8c34
-    mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
dc8c34
-    mod.mod_type = (char *)type_replicaCleanRUV;
dc8c34
-    mod.mod_bvalues = vals;
dc8c34
-    vals [0] = &val;
dc8c34
-    vals [1] = NULL;
dc8c34
-    val.bv_val = data;
dc8c34
-    mods[0] = &mod;
dc8c34
-    mods[1] = NULL;
dc8c34
-
dc8c34
-    replica_remove_cleanruv_data(r, data);
dc8c34
-
dc8c34
-    slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
-    slapi_modify_internal_pb (pb);
dc8c34
-    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
dc8c34
-    if (rc != LDAP_SUCCESS){
dc8c34
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to remove replica config "
dc8c34
-            "(%d), rid (%d)\n", rc, rid);
dc8c34
-    }
dc8c34
-    slapi_pblock_destroy (pb);
dc8c34
-    slapi_ch_free_string(&dn;;
dc8c34
-    /*
dc8c34
-     *  Now release the cleaned rid from the repl agmts
dc8c34
-     */
dc8c34
-    agmt_obj = agmtlist_get_first_agreement_for_replica (r);
dc8c34
-    while (agmt_obj){
dc8c34
-        agmt = (Repl_Agmt*)object_get_data (agmt_obj);
dc8c34
-        if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
dc8c34
-            agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
dc8c34
-            continue;
dc8c34
-        }
dc8c34
-        agmt_set_cleanruv_data(agmt, rid, CLEANRUV_RELEASED);
dc8c34
-        agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
dc8c34
+    /* now do the preset cleaned rids */
dc8c34
+    for(i = 0; i < CLEANRIDSIZ && pre_cleaned_rids[i] != rid; i++); /* found rid, stop */
dc8c34
+    for(; i < CLEANRIDSIZ; i++){
dc8c34
+        /* rewrite entire array */
dc8c34
+        pre_cleaned_rids[i] = pre_cleaned_rids[i + 1];
dc8c34
     }
dc8c34
+
dc8c34
+    slapi_rwlock_unlock(rid_lock);
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
@@ -2181,18 +2435,17 @@ int
dc8c34
 replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
dc8c34
         int *returncode, char *returntext, void *arg)
dc8c34
 {
dc8c34
-    PRThread *thread = NULL;
dc8c34
     struct berval *payload = NULL;
dc8c34
-    Slapi_Task *task = NULL;
dc8c34
-    Replica *replica;
dc8c34
-    ReplicaId rid;
dc8c34
     cleanruv_data *data = NULL;
dc8c34
+    PRThread *thread = NULL;
dc8c34
+    Slapi_Task *task = NULL;
dc8c34
     Slapi_DN *sdn = NULL;
dc8c34
+    Replica *replica;
dc8c34
+    ReplicaId rid;;
dc8c34
     Object *r;
dc8c34
-    CSN *maxcsn = NULL;
dc8c34
+    const char *certify_all;
dc8c34
     const char *base_dn;
dc8c34
     const char *rid_str;
dc8c34
-    const char *certify_all;
dc8c34
     char *ridstr = NULL;
dc8c34
     int rc = SLAPI_DSE_CALLBACK_OK;
dc8c34
 
dc8c34
@@ -2216,13 +2469,6 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
         goto out;
dc8c34
     }
dc8c34
-    if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
dc8c34
-        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing required attr \"replica-base-dn\"");
dc8c34
-        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
dc8c34
-        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
dc8c34
-        rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
-        goto out;
dc8c34
-    }
dc8c34
     certify_all = fetch_attr(e, "replica-certify-all", 0);
dc8c34
     /*
dc8c34
      *  Check the rid
dc8c34
@@ -2236,6 +2482,29 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
         goto out;
dc8c34
     }
dc8c34
+    if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
dc8c34
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Missing required attr \"replica-base-dn\"");
dc8c34
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
dc8c34
+        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
dc8c34
+        rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
+        goto out;
dc8c34
+    }
dc8c34
+    if(!is_cleaned_rid(rid) && !is_pre_cleaned_rid(rid)){
dc8c34
+        /* we are not cleaning this rid */
dc8c34
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is not being cleaned, nothing to abort.", rid);
dc8c34
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
dc8c34
+        *returncode = LDAP_UNWILLING_TO_PERFORM;
dc8c34
+        rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
+        goto out;
dc8c34
+    }
dc8c34
+    if(is_task_aborted(rid)){
dc8c34
+        /* we are already aborting this rid */
dc8c34
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Replica id (%d) is already being aborted", rid);
dc8c34
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "%s", returntext);
dc8c34
+        *returncode = LDAP_UNWILLING_TO_PERFORM;
dc8c34
+        rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
+        goto out;
dc8c34
+    }
dc8c34
     /*
dc8c34
      *  Get the replica object
dc8c34
      */
dc8c34
@@ -2248,7 +2517,7 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
dc8c34
         goto out;
dc8c34
     }
dc8c34
     /*
dc8c34
-     *  Check verify value
dc8c34
+     *  Check certify value
dc8c34
      */
dc8c34
     if(certify_all){
dc8c34
         if(strcasecmp(certify_all,"yes") && strcasecmp(certify_all,"no")){
dc8c34
@@ -2260,13 +2529,13 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
dc8c34
             goto out;
dc8c34
         }
dc8c34
     } else {
dc8c34
-        certify_all = "no";
dc8c34
+        certify_all = "yes";
dc8c34
     }
dc8c34
     /*
dc8c34
      *  Create payload
dc8c34
      */
dc8c34
     ridstr = slapi_ch_smprintf("%d:%s:%s", rid, base_dn, certify_all);
dc8c34
-    payload = create_ruv_payload(ridstr);
dc8c34
+    payload = create_cleanruv_payload(ridstr);
dc8c34
 
dc8c34
     if(payload == NULL){
dc8c34
         cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to create extended op payload, aborting task");
dc8c34
@@ -2278,8 +2547,6 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
dc8c34
      *  Stop the cleaning, and delete the rid
dc8c34
      */
dc8c34
     replica = (Replica*)object_get_data (r);
dc8c34
-    maxcsn = replica_get_cleanruv_maxcsn(replica, rid);
dc8c34
-    delete_cleaned_rid(replica, rid, maxcsn);
dc8c34
     add_aborted_rid(rid, replica, (char *)base_dn);
dc8c34
     stop_ruv_cleaning();
dc8c34
     /*
dc8c34
@@ -2308,11 +2575,11 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
dc8c34
         object_release(r);
dc8c34
         cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Unable to create abort thread.  Aborting task.");
dc8c34
         *returncode = LDAP_OPERATIONS_ERROR;
dc8c34
+        slapi_ch_free_string(&data->certify);
dc8c34
         rc = SLAPI_DSE_CALLBACK_ERROR;
dc8c34
     }
dc8c34
 
dc8c34
 out:
dc8c34
-    csn_free(&maxcsn);
dc8c34
     slapi_ch_free_string(&ridstr);
dc8c34
     slapi_sdn_free(&sdn;;
dc8c34
 
dc8c34
@@ -2337,6 +2604,8 @@ replica_abort_task_thread(void *arg)
dc8c34
     int interval = 10;
dc8c34
     int release_it = 0;
dc8c34
 
dc8c34
+    cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Aborting task for rid(%d)...",data->rid);
dc8c34
+
dc8c34
     /*
dc8c34
      *   Need to build the replica from the dn
dc8c34
      */
dc8c34
@@ -2414,8 +2683,12 @@ done:
dc8c34
         /*
dc8c34
          *  Clean up the config
dc8c34
          */
dc8c34
-        delete_aborted_rid(data->replica, data->rid, data->repl_root);
dc8c34
-        cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Successfully aborted cleanAllRUV task for rid(%d)", data->rid);
dc8c34
+        delete_aborted_rid(data->replica, data->rid, data->repl_root, 1); /* delete just the config, leave rid in memory */
dc8c34
+        if(strcasecmp(data->certify, "yes") == 0){
dc8c34
+            check_replicas_are_done_aborting(data);
dc8c34
+        }
dc8c34
+        delete_aborted_rid(data->replica, data->rid, data->repl_root, 0); /* remove the in-memory aborted rid */
dc8c34
+        cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Successfully aborted task for rid(%d)", data->rid);
dc8c34
     }
dc8c34
     if(data->task){
dc8c34
         slapi_task_finish(data->task, agmt_not_notified);
dc8c34
@@ -2437,10 +2710,10 @@ replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct ber
dc8c34
     Repl_Connection *conn = NULL;
dc8c34
     ConnResult crc = 0;
dc8c34
     int msgid = 0;
dc8c34
-    int rc = 0;
dc8c34
+    int rc = -1;
dc8c34
 
dc8c34
     if((conn = conn_new(ra)) == NULL){
dc8c34
-        return -1;
dc8c34
+        return rc;
dc8c34
     }
dc8c34
     if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
         crc = conn_send_extended_operation(conn, REPL_ABORT_CLEANRUV_OID, payload, NULL, &msgid);
dc8c34
@@ -2462,186 +2735,262 @@ replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct ber
dc8c34
 
dc8c34
 
dc8c34
 static int
dc8c34
-replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result)
dc8c34
+replica_cleanallruv_send_extop(Repl_Agmt *ra, cleanruv_data *clean_data, int check_result)
dc8c34
 {
dc8c34
     Repl_Connection *conn = NULL;
dc8c34
     ConnResult crc = 0;
dc8c34
     int msgid = 0;
dc8c34
-    int rc = 0;
dc8c34
+    int rc = -1;
dc8c34
 
dc8c34
     if((conn = conn_new(ra)) == NULL){
dc8c34
-        return -1;
dc8c34
+        return rc;
dc8c34
     }
dc8c34
     if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
-        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, payload, NULL, &msgid);
dc8c34
+        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, clean_data->payload, NULL, &msgid);
dc8c34
         if(crc == CONN_OPERATION_SUCCESS && check_result){
dc8c34
             struct berval *retsdata = NULL;
dc8c34
             char *retoid = NULL;
dc8c34
 
dc8c34
             crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
dc8c34
             if (CONN_OPERATION_SUCCESS == crc ){
dc8c34
-                struct berval **ruv_bervals = NULL;
dc8c34
-                struct berval *data = NULL;
dc8c34
-                char *data_guid = NULL;
dc8c34
-
dc8c34
-                decode_repl_ext_response(retsdata, &rc, &ruv_bervals, &data_guid, &data);
dc8c34
-                /* just free everything, we only wanted "rc" */
dc8c34
-                slapi_ch_free_string(&data_guid);
dc8c34
-                if(data)
dc8c34
-                    ber_bvfree(data);
dc8c34
-                if (ruv_bervals)
dc8c34
-                    ber_bvecfree(ruv_bervals);
dc8c34
-
dc8c34
-                if(rc == 0 ){ /* rc == 1 is success */
dc8c34
-                    cleanruv_log(task, CLEANALLRUV_ID,"Replica %s does not support the CLEANALLRUV task.  Sending replica CLEANRUV task...",
dc8c34
+                char *response = NULL;
dc8c34
+
dc8c34
+                decode_cleanruv_payload(retsdata, &response);
dc8c34
+                if(response && strcmp(response,CLEANRUV_ACCEPTED) == 0){
dc8c34
+                    /* extop was accepted */
dc8c34
+                    rc = 0;
dc8c34
+                } else {
dc8c34
+                    cleanruv_log(clean_data->task, CLEANALLRUV_ID,"Replica %s does not support the CLEANALLRUV task.  Sending replica CLEANRUV task...",
dc8c34
                         slapi_sdn_get_dn(agmt_get_dn_byref(ra)));
dc8c34
                     /*
dc8c34
                      *  Ok, this replica doesn't know about CLEANALLRUV, so just manually
dc8c34
                      *  add the CLEANRUV task to the replica.
dc8c34
                      */
dc8c34
-                    replica_send_cleanruv_task(ra, rid, task);
dc8c34
-                } else {
dc8c34
-                    /* extop was accepted */
dc8c34
-                    rc = 0;
dc8c34
+                    replica_send_cleanruv_task(ra, clean_data);
dc8c34
                 }
dc8c34
-                if (NULL != retoid)
dc8c34
-                    ldap_memfree(retoid);
dc8c34
                 if (NULL != retsdata)
dc8c34
                     ber_bvfree(retsdata);
dc8c34
+                slapi_ch_free_string(&retoid);
dc8c34
+                slapi_ch_free_string(&response);
dc8c34
             }
dc8c34
-            agmt_set_cleanruv_data(ra, rid, CLEANRUV_NOTIFIED);
dc8c34
         } else {
dc8c34
             /*
dc8c34
              * success or failure, just return the error code
dc8c34
              */
dc8c34
             rc = crc;
dc8c34
         }
dc8c34
-    } else {
dc8c34
-        rc =-1;
dc8c34
     }
dc8c34
     conn_delete_internal_ext(conn);
dc8c34
 
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
+static CSN*
dc8c34
+replica_cleanallruv_find_maxcsn(Replica *replica, ReplicaId rid, char *basedn)
dc8c34
+{
dc8c34
+    Object *agmt_obj;
dc8c34
+    Repl_Agmt *agmt;
dc8c34
+    char *rid_text;
dc8c34
+    CSN *maxcsn = NULL, *topcsn = NULL;
dc8c34
+    int done = 1, found = 0;
dc8c34
+    int interval = 10;
dc8c34
+
dc8c34
+    rid_text = slapi_ch_smprintf("%d", rid);
dc8c34
+
dc8c34
+    while(done && !is_task_aborted(rid) && !slapi_is_shutting_down()){
dc8c34
+        agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
dc8c34
+        if(agmt_obj == NULL){
dc8c34
+            break;
dc8c34
+        }
dc8c34
+        while (agmt_obj && !slapi_is_shutting_down()){
dc8c34
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
dc8c34
+            if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
dc8c34
+                agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
dc8c34
+                done = 0;
dc8c34
+                continue;
dc8c34
+            }
dc8c34
+            if(replica_cleanallruv_get_replica_maxcsn(agmt, rid_text, basedn, &maxcsn) == 0){
dc8c34
+                if(maxcsn == NULL){
dc8c34
+                    agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
dc8c34
+                    continue;
dc8c34
+                }
dc8c34
+                found = 1;
dc8c34
+                if(topcsn == NULL){
dc8c34
+                    topcsn = maxcsn;
dc8c34
+                } else {
dc8c34
+                    if(csn_compare(topcsn, maxcsn) < 0){
dc8c34
+                        csn_free(&topcsn);
dc8c34
+                        topcsn = maxcsn;
dc8c34
+                    } else {
dc8c34
+                        csn_free(&maxcsn);
dc8c34
+                    }
dc8c34
+                }
dc8c34
+                done = 0;
dc8c34
+            } else {
dc8c34
+                done = 1;
dc8c34
+                break;
dc8c34
+            }
dc8c34
+            agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
dc8c34
+        } /* agmt while */
dc8c34
+        if(done == 0 || is_task_aborted(rid) ){
dc8c34
+            break;
dc8c34
+        }
dc8c34
+        if(!found){
dc8c34
+            /* we could not find any maxcsn's - already cleaned? */
dc8c34
+            return NULL;
dc8c34
+        }
dc8c34
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: replica_cleanallruv_find_maxcsn: Not all replicas online, retrying in %d seconds\n",interval);
dc8c34
+        PR_Lock( notify_lock );
dc8c34
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
dc8c34
+        PR_Unlock( notify_lock );
dc8c34
+
dc8c34
+        if(interval < 14400){ /* 4 hour max */
dc8c34
+            interval = interval * 2;
dc8c34
+        } else {
dc8c34
+            interval = 14400;
dc8c34
+        }
dc8c34
+    }
dc8c34
+    slapi_ch_free_string(&rid_text);
dc8c34
+
dc8c34
+    if(is_task_aborted(rid)){
dc8c34
+        return NULL;
dc8c34
+    }
dc8c34
+
dc8c34
+    return topcsn;
dc8c34
+}
dc8c34
+
dc8c34
 static int
dc8c34
-replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task)
dc8c34
+replica_cleanallruv_get_replica_maxcsn(Repl_Agmt *agmt, char *rid_text, char *basedn, CSN **csn)
dc8c34
 {
dc8c34
     Repl_Connection *conn = NULL;
dc8c34
-    LDAP *ld;
dc8c34
-    Slapi_DN *sdn;
dc8c34
-    struct berval **vals;
dc8c34
-    LDAPMessage *result = NULL, *entry = NULL;
dc8c34
-    BerElement *ber;
dc8c34
-    char *attrs[2];
dc8c34
-    char *attr = NULL;
dc8c34
-    char *iter = NULL;
dc8c34
-    char *ruv_part = NULL;
dc8c34
-    int found_rid = 0;
dc8c34
-    int part_count = 0;
dc8c34
-    int rc = 0, i;
dc8c34
+    ConnResult crc = -1;
dc8c34
+    struct berval *payload = NULL;
dc8c34
+    CSN *maxcsn = NULL;
dc8c34
+    char *data = NULL;
dc8c34
+    int msgid = 0;
dc8c34
 
dc8c34
     if((conn = conn_new(agmt)) == NULL){
dc8c34
         return -1;
dc8c34
     }
dc8c34
 
dc8c34
+    data = slapi_ch_smprintf("%s:%s",rid_text, basedn);
dc8c34
+    payload = create_cleanruv_payload(data);
dc8c34
+
dc8c34
     if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
-        attrs[0] = "nsds50ruv";
dc8c34
-        attrs[1] = NULL;
dc8c34
-        ld = conn_get_ldap(conn);
dc8c34
-        if(ld == NULL){
dc8c34
-            conn_delete_internal_ext(conn);
dc8c34
-            return -1;
dc8c34
-        }
dc8c34
-        sdn = agmt_get_replarea(agmt);
dc8c34
-        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
dc8c34
-            "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
dc8c34
-            attrs, 0, NULL, NULL, NULL, 0, &result);
dc8c34
-        slapi_sdn_free(&sdn;;
dc8c34
-        if(rc != LDAP_SUCCESS){
dc8c34
-        	cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
dc8c34
-                "agmt (%s) error (%d), will retry later.", agmt_get_long_name(agmt), rc);
dc8c34
-            conn_delete_internal_ext(conn);
dc8c34
-            return -1;
dc8c34
-        }
dc8c34
-        entry = ldap_first_entry( ld, result );
dc8c34
-        if ( entry != NULL ) {
dc8c34
-            for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
dc8c34
-                /* make sure the attribute is nsds50ruv */
dc8c34
-                if(strcasecmp(attr,"nsds50ruv") != 0){
dc8c34
-                    ldap_memfree( attr );
dc8c34
-                    continue;
dc8c34
+        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_GET_MAXCSN_OID, payload, NULL, &msgid);
dc8c34
+        if(crc == CONN_OPERATION_SUCCESS){
dc8c34
+            struct berval *retsdata = NULL;
dc8c34
+            char *retoid = NULL;
dc8c34
+
dc8c34
+            crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
dc8c34
+            if (CONN_OPERATION_SUCCESS == crc ){
dc8c34
+                char *remote_maxcsn = NULL;
dc8c34
+
dc8c34
+                decode_cleanruv_payload(retsdata, &remote_maxcsn);
dc8c34
+                if(remote_maxcsn && strcmp(remote_maxcsn, CLEANRUV_NO_MAXCSN)){
dc8c34
+                    maxcsn = csn_new();
dc8c34
+                    csn_init_by_string(maxcsn, remote_maxcsn);
dc8c34
+                    *csn = maxcsn;
dc8c34
+                } else {
dc8c34
+                    /* no csn */
dc8c34
+                    *csn = NULL;
dc8c34
                 }
dc8c34
-                found_rid = 0;
dc8c34
-                if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
dc8c34
-                    for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
dc8c34
-                        /* look for this replica */
dc8c34
-                        if(strstr(vals[i]->bv_val, rid_text)){
dc8c34
-                            found_rid = 1;
dc8c34
-                            /* get the max csn compare it to our known max csn */
dc8c34
-                            ruv_part = ldap_utf8strtok_r(vals[i]->bv_val, " ", &iter);
dc8c34
-                            for(part_count = 1; ruv_part && part_count < 5; part_count++){
dc8c34
-                                ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
dc8c34
-                            }
dc8c34
-                            if(part_count == 5 && ruv_part){
dc8c34
-                                /* we have the maxcsn */
dc8c34
-                                if(strcmp(ruv_part, maxcsn)){
dc8c34
-                                    /* we are not caught up yet, free, and return */
dc8c34
-                                    ldap_value_free_len(vals);
dc8c34
-                                    ldap_memfree( attr );
dc8c34
-                                    ldap_msgfree( result );
dc8c34
-                                    if(ber){
dc8c34
-                                        ber_free( ber, 0 );
dc8c34
-                                    }
dc8c34
-                                    conn_delete_internal_ext(conn);
dc8c34
-                                    return -1;
dc8c34
-                                } else {
dc8c34
-                                    /* ok this replica has all the updates from the deleted replica */
dc8c34
-                                    rc = 0;
dc8c34
-                                }
dc8c34
-                            } else {
dc8c34
-                                /* there is no maxcsn for this rid - treat it as caught up */
dc8c34
-                                rc = 0;
dc8c34
-                            }
dc8c34
-                        }
dc8c34
-                    }
dc8c34
-                    if(!found_rid){
dc8c34
-                        /* must have been cleaned already */
dc8c34
+                slapi_ch_free_string(&retoid);
dc8c34
+                slapi_ch_free_string(&remote_maxcsn);
dc8c34
+                if (NULL != retsdata)
dc8c34
+                    ber_bvfree(retsdata);
dc8c34
+            }
dc8c34
+        }
dc8c34
+    }
dc8c34
+    conn_delete_internal_ext(conn);
dc8c34
+    slapi_ch_free_string(&data);
dc8c34
+    if(payload)
dc8c34
+        ber_bvfree(payload);
dc8c34
+
dc8c34
+    return (int)crc;
dc8c34
+}
dc8c34
+
dc8c34
+static int
dc8c34
+replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *basedn, char *rid_text, char *maxcsn, Slapi_Task *task)
dc8c34
+{
dc8c34
+    Repl_Connection *conn = NULL;
dc8c34
+    ConnResult crc = 0;
dc8c34
+    struct berval *payload = NULL;
dc8c34
+    char *data = NULL;
dc8c34
+    int msgid = 0;
dc8c34
+    int rc = -1;
dc8c34
+
dc8c34
+    if((conn = conn_new(agmt)) == NULL){
dc8c34
+        return -1;
dc8c34
+    }
dc8c34
+
dc8c34
+    data = slapi_ch_smprintf("%s:%s",rid_text, basedn);
dc8c34
+    payload = create_cleanruv_payload(data);
dc8c34
+
dc8c34
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
+        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_GET_MAXCSN_OID, payload, NULL, &msgid);
dc8c34
+        if(crc == CONN_OPERATION_SUCCESS){
dc8c34
+            struct berval *retsdata = NULL;
dc8c34
+            char *retoid = NULL;
dc8c34
+
dc8c34
+            crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
dc8c34
+            if (CONN_OPERATION_SUCCESS == crc ){
dc8c34
+                char *remote_maxcsn = NULL;
dc8c34
+
dc8c34
+                decode_cleanruv_payload(retsdata, &remote_maxcsn);
dc8c34
+                if(remote_maxcsn && strcmp(remote_maxcsn, CLEANRUV_NO_MAXCSN)){
dc8c34
+                    CSN *max, *repl_max;
dc8c34
+
dc8c34
+                    max = csn_new();
dc8c34
+                    repl_max = csn_new();
dc8c34
+                    csn_init_by_string(max, maxcsn);
dc8c34
+                    csn_init_by_string(repl_max, remote_maxcsn);
dc8c34
+                    if(csn_compare (repl_max, max) < 0){
dc8c34
+                        /* we are not caught up yet, free, and return */
dc8c34
+                        cleanruv_log(task, CLEANALLRUV_ID,"Replica maxcsn (%s) is not caught up with deleted replica's maxcsn(%s)",
dc8c34
+                            remote_maxcsn, maxcsn);
dc8c34
+                        rc = -1;
dc8c34
+                    } else {
dc8c34
+                        /* ok this replica is caught up */
dc8c34
                         rc = 0;
dc8c34
                     }
dc8c34
-                    ldap_value_free_len(vals);
dc8c34
+                    csn_free(&max;;
dc8c34
+                    csn_free(&repl_max);
dc8c34
+                } else {
dc8c34
+                    /* no remote_maxcsn - return success */
dc8c34
+                    rc = 0;
dc8c34
                 }
dc8c34
-                ldap_memfree( attr );
dc8c34
-            }
dc8c34
-            if ( ber != NULL ) {
dc8c34
-                ber_free( ber, 0 );
dc8c34
-            }
dc8c34
-        }
dc8c34
-        if(result)
dc8c34
-            ldap_msgfree( result );
dc8c34
-    } else {
dc8c34
-        rc = -1;
dc8c34
+                slapi_ch_free_string(&retoid);
dc8c34
+                slapi_ch_free_string(&remote_maxcsn);
dc8c34
+                if (NULL != retsdata)
dc8c34
+                    ber_bvfree(retsdata);
dc8c34
+             }
dc8c34
+         }
dc8c34
     }
dc8c34
     conn_delete_internal_ext(conn);
dc8c34
+    slapi_ch_free_string(&data);
dc8c34
+    if(payload)
dc8c34
+        ber_bvfree(payload);
dc8c34
 
dc8c34
-    return rc;
dc8c34
+     return rc;
dc8c34
 }
dc8c34
 
dc8c34
+
dc8c34
 static int
dc8c34
 replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
dc8c34
 {
dc8c34
     Repl_Connection *conn = NULL;
dc8c34
     LDAP *ld = NULL;
dc8c34
     LDAPMessage *result = NULL;
dc8c34
-    int rc = 0;
dc8c34
+    int rc = -1;
dc8c34
 
dc8c34
     if((conn = conn_new(agmt)) == NULL){
dc8c34
-        return -1;
dc8c34
+        return rc;
dc8c34
     }
dc8c34
     if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
         ld = conn_get_ldap(conn);
dc8c34
         if(ld == NULL){
dc8c34
-            slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_task: failed to get LDAP "
dc8c34
+            slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "CleanAllRUV_task: failed to get LDAP "
dc8c34
                 "handle from the replication agmt (%s).  Moving on to the next agmt.\n",agmt_get_long_name(agmt));
dc8c34
             conn_delete_internal_ext(conn);
dc8c34
             return -1;
dc8c34
@@ -2655,8 +3004,6 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
dc8c34
         }
dc8c34
         if(result)
dc8c34
             ldap_msgfree( result );
dc8c34
-    } else {
dc8c34
-        rc = -1;
dc8c34
     }
dc8c34
     conn_delete_internal_ext(conn);
dc8c34
 
dc8c34
@@ -2664,83 +3011,51 @@ replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
dc8c34
 }
dc8c34
 
dc8c34
 static int
dc8c34
-replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task)
dc8c34
+replica_cleanallruv_check_ruv(char *repl_root, Repl_Agmt *agmt, char *rid_text, Slapi_Task *task)
dc8c34
 {
dc8c34
     Repl_Connection *conn = NULL;
dc8c34
-    BerElement *ber = NULL;
dc8c34
-    struct berval **vals = NULL;
dc8c34
-    LDAPMessage *result = NULL, *entry = NULL;
dc8c34
-    LDAP *ld = NULL;
dc8c34
-    Slapi_DN *sdn;
dc8c34
-    char *attrs[2];
dc8c34
-    char *attr = NULL;
dc8c34
-    int rc = 0, i;
dc8c34
+    ConnResult crc = 0;
dc8c34
+    struct berval *payload = NULL;
dc8c34
+    char *data = NULL;
dc8c34
+    int msgid = 0;
dc8c34
+    int rc = -1;
dc8c34
 
dc8c34
-    if((conn = conn_new(ra)) == NULL){
dc8c34
-        return -1;
dc8c34
+    if((conn = conn_new(agmt)) == NULL){
dc8c34
+        return rc;
dc8c34
     }
dc8c34
+
dc8c34
+    data = slapi_ch_smprintf("%s:%s",rid_text, repl_root);
dc8c34
+    payload = create_cleanruv_payload(data);
dc8c34
+
dc8c34
     if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
dc8c34
-        attrs[0] = "nsds50ruv";
dc8c34
-        attrs[1] = NULL;
dc8c34
-        ld = conn_get_ldap(conn);
dc8c34
-        if(ld == NULL){
dc8c34
-        	cleanruv_log(task, CLEANALLRUV_ID,"Failed to get LDAP handle from "
dc8c34
-                "the replication agmt (%s).  Moving on to the next agmt.",agmt_get_long_name(ra));
dc8c34
-            rc = -1;
dc8c34
-            goto done;
dc8c34
-        }
dc8c34
+        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_GET_MAXCSN_OID, payload, NULL, &msgid);
dc8c34
+        if(crc == CONN_OPERATION_SUCCESS){
dc8c34
+            struct berval *retsdata = NULL;
dc8c34
+            char *retoid = NULL;
dc8c34
 
dc8c34
-        sdn = agmt_get_replarea(ra);
dc8c34
-        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
dc8c34
-            "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
dc8c34
-            attrs, 0, NULL, NULL, NULL, 0, &result);
dc8c34
-        slapi_sdn_free(&sdn;;
dc8c34
-        if(rc != LDAP_SUCCESS){
dc8c34
-            cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
dc8c34
-                "agmt (%s) error (%d), will retry later.", agmt_get_long_name(ra), rc);
dc8c34
-            rc = -1;
dc8c34
-            goto done;
dc8c34
-        }
dc8c34
-        entry = ldap_first_entry( ld, result );
dc8c34
-        if ( entry != NULL ) {
dc8c34
-            for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
dc8c34
-                /* make sure the attribute is nsds50ruv */
dc8c34
-                if(strcasecmp(attr,"nsds50ruv") != 0){
dc8c34
-                    ldap_memfree( attr );
dc8c34
-                    continue;
dc8c34
-                }
dc8c34
-                if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
dc8c34
-                    for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
dc8c34
-                        /* look for this replica */
dc8c34
-                        if(strstr(vals[i]->bv_val, rid_text)){
dc8c34
-                            /* rid has not been cleaned yet, free and return */
dc8c34
-                            rc = -1;
dc8c34
-                            ldap_value_free_len(vals);
dc8c34
-                            ldap_memfree( attr );
dc8c34
-                            if ( ber != NULL ) {
dc8c34
-                                ber_free( ber, 0 );
dc8c34
-                                ber = NULL;
dc8c34
-                            }
dc8c34
-                            goto done;
dc8c34
-                        } else {
dc8c34
-                            rc = 0;
dc8c34
-                        }
dc8c34
-                    }
dc8c34
-                    ldap_value_free_len(vals);
dc8c34
+            crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
dc8c34
+            if (CONN_OPERATION_SUCCESS == crc ){
dc8c34
+                char *remote_maxcsn = NULL;
dc8c34
+
dc8c34
+                decode_cleanruv_payload(retsdata, &remote_maxcsn);
dc8c34
+                if(remote_maxcsn && strcmp(remote_maxcsn, CLEANRUV_NO_MAXCSN)){
dc8c34
+                    /* remote replica still has dirty RUV element */
dc8c34
+                    rc = -1;
dc8c34
+                } else {
dc8c34
+                   /* no maxcsn = we're clean */
dc8c34
+                   rc = 0;
dc8c34
                 }
dc8c34
-                ldap_memfree( attr );
dc8c34
-            } /* for loop */
dc8c34
-            if ( ber != NULL ) {
dc8c34
-                ber_free( ber, 0 );
dc8c34
+                slapi_ch_free_string(&retoid);
dc8c34
+                slapi_ch_free_string(&remote_maxcsn);
dc8c34
+                if (NULL != retsdata)
dc8c34
+                    ber_bvfree(retsdata);
dc8c34
             }
dc8c34
         }
dc8c34
-done:
dc8c34
-        if(result)
dc8c34
-            ldap_msgfree( result );
dc8c34
-    } else {
dc8c34
-        return -1;
dc8c34
     }
dc8c34
     conn_delete_internal_ext(conn);
dc8c34
+    slapi_ch_free_string(&data);
dc8c34
+    if(payload)
dc8c34
+        ber_bvfree(payload);
dc8c34
 
dc8c34
     return rc;
dc8c34
 }
dc8c34
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
dc8c34
index 3a6f422..e842c62 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl_extop.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl_extop.c
dc8c34
@@ -1451,7 +1451,6 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 	cleanruv_data *data;
dc8c34
 	Replica *r;
dc8c34
 	ReplicaId rid;
dc8c34
-	CSN *maxcsn = NULL;
dc8c34
 	struct berval *extop_payload = NULL;
dc8c34
 	char *extop_oid;
dc8c34
 	char *repl_root;
dc8c34
@@ -1463,7 +1462,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
dc8c34
 	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
dc8c34
 
dc8c34
-	if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_OID) != 0 ||
dc8c34
+	if (NULL == extop_oid || strcmp(extop_oid, REPL_ABORT_CLEANRUV_OID) != 0 ||
dc8c34
 		NULL == extop_payload || NULL == extop_payload->bv_val){
dc8c34
 		/* something is wrong, error out */
dc8c34
 		return LDAP_OPERATIONS_ERROR;
dc8c34
@@ -1472,24 +1471,24 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 	 *  Decode the payload, and grab our settings
dc8c34
 	 */
dc8c34
 	if(decode_cleanruv_payload(extop_payload, &payload)){
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: failed to decode payload.  Aborting ext op\n");
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to decode payload.  Aborting ext op\n");
dc8c34
 		return LDAP_OPERATIONS_ERROR;
dc8c34
 	}
dc8c34
 	rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
dc8c34
 	repl_root = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
 	certify_all = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
 
dc8c34
-	if(!is_cleaned_rid(rid) || is_task_aborted(rid)){
dc8c34
+	if(!is_cleaned_rid(rid) || !is_pre_cleaned_rid(rid) || is_task_aborted(rid)){
dc8c34
 		/* This replica has already been aborted, or was never cleaned, or already finished cleaning */
dc8c34
 		goto out;
dc8c34
 	} else {
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: aborting cleanallruv task for rid(%d)\n", rid);
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: aborting cleanallruv task for rid(%d)\n", rid);
dc8c34
 	}
dc8c34
 	/*
dc8c34
 	 *  Get the node, so we can get the replica and its agreements
dc8c34
 	 */
dc8c34
 	if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: failed to get replication node "
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to get replication node "
dc8c34
 			"from (%s), aborting operation\n", repl_root);
dc8c34
 		rc = LDAP_OPERATIONS_ERROR;
dc8c34
 		goto out;
dc8c34
@@ -1498,14 +1497,14 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 		object_acquire (mtnode_ext->replica);
dc8c34
 		release_it = 1;
dc8c34
 	} else {
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: replica is missing from (%s), "
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica is missing from (%s), "
dc8c34
 			"aborting operation\n",repl_root);
dc8c34
 		rc = LDAP_OPERATIONS_ERROR;
dc8c34
 		goto out;
dc8c34
 	}
dc8c34
 	r = (Replica*)object_get_data (mtnode_ext->replica);
dc8c34
 	if(r == NULL){
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: replica is NULL, aborting task\n");
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica is NULL, aborting task\n");
dc8c34
 		rc = LDAP_OPERATIONS_ERROR;
dc8c34
 		goto out;
dc8c34
 	}
dc8c34
@@ -1514,7 +1513,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 	 */
dc8c34
 	data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
dc8c34
 	if (data == NULL) {
dc8c34
-		slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort cleanAllRUV task: failed to allocate "
dc8c34
+		slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort CleanAllRUV Task: failed to allocate "
dc8c34
 			"abort_cleanruv_data.  Aborting task.\n");
dc8c34
 		rc = LDAP_OPERATIONS_ERROR;
dc8c34
 		goto out;
dc8c34
@@ -1528,11 +1527,8 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 	data->repl_root = slapi_ch_strdup(repl_root);
dc8c34
 	data->certify = slapi_ch_strdup(certify_all);
dc8c34
 	/*
dc8c34
-	 *  Stop the cleaning, and delete the rid
dc8c34
+	 *  Set the aborted rid and stop the cleaning
dc8c34
 	 */
dc8c34
-	maxcsn = replica_get_cleanruv_maxcsn(r, rid);
dc8c34
-	delete_cleaned_rid(r, rid, maxcsn);
dc8c34
-	csn_free(&maxcsn);
dc8c34
 	add_aborted_rid(rid, r, repl_root);
dc8c34
 	stop_ruv_cleaning();
dc8c34
 	/*
dc8c34
@@ -1542,7 +1538,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
dc8c34
 			(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
dc8c34
 			PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
dc8c34
 	if (thread == NULL) {
dc8c34
-		slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort cleanAllRUV task: unable to create abort "
dc8c34
+		slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort CleanAllRUV Task: unable to create abort "
dc8c34
 			"thread.  Aborting task.\n");
dc8c34
 		release_it = 1; /* have to release mtnode_ext->replica now */
dc8c34
 		slapi_ch_free_string(&data->repl_root);
dc8c34
@@ -1583,10 +1579,11 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 	struct berval *extop_payload;
dc8c34
 	struct berval *resp_bval = NULL;
dc8c34
 	BerElement *resp_bere = NULL;
dc8c34
-	char *extop_oid;
dc8c34
-	char *repl_root;
dc8c34
 	char *payload = NULL;
dc8c34
 	char *csnstr = NULL;
dc8c34
+	char *force = NULL;
dc8c34
+	char *extop_oid;
dc8c34
+	char *repl_root;
dc8c34
 	char *iter;
dc8c34
 	int release_it = 0;
dc8c34
 	int rid = 0;
dc8c34
@@ -1604,28 +1601,31 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 	 *  Decode the payload
dc8c34
 	 */
dc8c34
 	if(decode_cleanruv_payload(extop_payload, &payload)){
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to decode payload.  Aborting ext op\n");
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to decode payload.  Aborting ext op\n");
dc8c34
 		goto free_and_return;
dc8c34
 	}
dc8c34
 	rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
dc8c34
 	repl_root = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
 	csnstr = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
+	force = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
+	if(force == NULL){
dc8c34
+		force = "no";
dc8c34
+	}
dc8c34
 	maxcsn = csn_new();
dc8c34
 	csn_init_by_string(maxcsn, csnstr);
dc8c34
 	/*
dc8c34
 	 *  If we already cleaned this server, just return success
dc8c34
 	 */
dc8c34
-	if(is_cleaned_rid(rid)){
dc8c34
+	if(is_cleaned_rid(rid) || is_pre_cleaned_rid(rid) || is_task_aborted(rid)){
dc8c34
 		csn_free(&maxcsn);
dc8c34
 		rc = LDAP_SUCCESS;
dc8c34
 		goto free_and_return;
dc8c34
 	}
dc8c34
-
dc8c34
 	/*
dc8c34
 	 *  Get the node, so we can get the replica and its agreements
dc8c34
 	 */
dc8c34
 	if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to get replication node "
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to get replication node "
dc8c34
 			"from (%s), aborting operation\n", repl_root);
dc8c34
 		goto free_and_return;
dc8c34
 	}
dc8c34
@@ -1634,14 +1634,14 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 		object_acquire (mtnode_ext->replica);
dc8c34
 		release_it = 1;
dc8c34
 	} else {
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is missing from (%s), "
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: replica is missing from (%s), "
dc8c34
 			"aborting operation\n",repl_root);
dc8c34
 		goto free_and_return;
dc8c34
 	}
dc8c34
 
dc8c34
 	r = (Replica*)object_get_data (mtnode_ext->replica);
dc8c34
 	if(r == NULL){
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is NULL, aborting task\n");
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: replica is NULL, aborting task\n");
dc8c34
 		goto free_and_return;
dc8c34
 	}
dc8c34
 
dc8c34
@@ -1651,10 +1651,10 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 		 *
dc8c34
 		 *  This will also release mtnode_ext->replica
dc8c34
 		 */
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: launching cleanAllRUV thread...\n");
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: launching cleanAllRUV thread...\n");
dc8c34
 		data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
dc8c34
 		if (data == NULL) {
dc8c34
-			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to allocate "
dc8c34
+			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to allocate "
dc8c34
 				"cleanruv_Data\n");
dc8c34
 			goto free_and_return;
dc8c34
 		}
dc8c34
@@ -1664,15 +1664,19 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 		data->task = NULL;
dc8c34
 		data->maxcsn = maxcsn;
dc8c34
 		data->payload = slapi_ch_bvdup(extop_payload);
dc8c34
+		data->force = slapi_ch_strdup(force);
dc8c34
+		data->repl_root = slapi_ch_strdup(repl_root);
dc8c34
 
dc8c34
 		thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
dc8c34
 				(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
dc8c34
 				PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
dc8c34
 		if (thread == NULL) {
dc8c34
-			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: unable to create cleanAllRUV "
dc8c34
+			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: unable to create cleanAllRUV "
dc8c34
 				"monitoring thread.  Aborting task.\n");
dc8c34
 			ber_bvfree(data->payload);
dc8c34
 			data->payload = NULL;
dc8c34
+			slapi_ch_free_string(&data->force);
dc8c34
+			slapi_ch_free_string(&data->repl_root);
dc8c34
 			slapi_ch_free((void **)&data);
dc8c34
 		} else {
dc8c34
 			release_it = 0; /* thread will release data->repl_obj == mtnode_ext->replica */
dc8c34
@@ -1694,18 +1698,18 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 				/* we've already been cleaned */
dc8c34
 				break;
dc8c34
 			}
dc8c34
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: checking if we're caught up...\n");
dc8c34
-			if(ruv_covers_csn_cleanallruv(ruv,maxcsn) || csn_get_replicaid(maxcsn) == 0){
dc8c34
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: checking if we're caught up...\n");
dc8c34
+			if(ruv_covers_csn_cleanallruv(ruv,maxcsn) || csn_get_replicaid(maxcsn) == 0|| strcmp(force,"yes") == 0){
dc8c34
 				/* We are caught up */
dc8c34
 				break;
dc8c34
 			} else {
dc8c34
 				char csnstr[CSN_STRSIZE];
dc8c34
 				csn_as_string(maxcsn, PR_FALSE, csnstr);
dc8c34
-				slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: not ruv caught up maxcsn(%s)\n", csnstr);
dc8c34
+				slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: not ruv caught up maxcsn(%s)\n", csnstr);
dc8c34
 			}
dc8c34
 			DS_Sleep(PR_SecondsToInterval(5));
dc8c34
 		}
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: we're caught up...\n");
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: we're caught up...\n");
dc8c34
 		/*
dc8c34
 		 *  Set cleaned rid in memory only - does not survive a server restart
dc8c34
 		 */
dc8c34
@@ -1721,8 +1725,8 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
dc8c34
 		 *  This read-only replica has no easy way to tell when it's safe to release the rid.
dc8c34
 		 *  So we won't release it, not until a server restart.
dc8c34
 		 */
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: You must restart the server if you want to reuse rid(%d).\n", rid);
dc8c34
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Successfully cleaned rid(%d).\n", rid);
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: You must restart the server if you want to reuse rid(%d).\n", rid);
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: Successfully cleaned rid(%d).\n", rid);
dc8c34
 		rc = LDAP_SUCCESS;
dc8c34
 	}
dc8c34
 
dc8c34
@@ -1737,10 +1741,120 @@ free_and_return:
dc8c34
 	 *   Craft a message so we know this replica supports the task
dc8c34
 	 */
dc8c34
 	if ((resp_bere = der_alloc())){
dc8c34
+		ber_printf(resp_bere, "{s}", CLEANRUV_ACCEPTED);
dc8c34
+		ber_flatten(resp_bere, &resp_bval);
dc8c34
+		slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
dc8c34
+		slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
dc8c34
+		/* resp_bere */
dc8c34
+		if (NULL != resp_bere)
dc8c34
+		{
dc8c34
+			ber_free(resp_bere, 1);
dc8c34
+		}
dc8c34
+		/* resp_bval */
dc8c34
+		if (NULL != resp_bval)
dc8c34
+		{
dc8c34
+			ber_bvfree(resp_bval);
dc8c34
+		}
dc8c34
+		/* tell extendop code that we have already sent the result */
dc8c34
+		rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
dc8c34
+	} else {
dc8c34
+		rc = LDAP_OPERATIONS_ERROR;
dc8c34
+	}
dc8c34
 
dc8c34
-		ber_int_t response = 1;
dc8c34
+	return rc;
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Get the max csn for the designated repl area
dc8c34
+ */
dc8c34
+int
dc8c34
+multimaster_extop_cleanruv_get_maxcsn(Slapi_PBlock *pb)
dc8c34
+{
dc8c34
+	Slapi_PBlock *search_pb = NULL;
dc8c34
+	Slapi_Entry **entries = NULL;
dc8c34
+	struct berval *resp_bval = NULL;
dc8c34
+	struct berval *extop_payload;
dc8c34
+	BerElement *resp_bere = NULL;
dc8c34
+	char **ruv_elements = NULL;
dc8c34
+	char *extop_oid = NULL;
dc8c34
+	char *ruv_part = NULL;
dc8c34
+	char *base_dn = NULL;
dc8c34
+	char *payload = NULL;
dc8c34
+	char *maxcsn = NULL;
dc8c34
+	char *filter = NULL;
dc8c34
+	char *ridstr = NULL;
dc8c34
+	char *iter = NULL;
dc8c34
+	char *attrs[2];
dc8c34
+	int part_count = 0;
dc8c34
+	int rid = 0;
dc8c34
+	int res = 0;
dc8c34
+	int rc = LDAP_OPERATIONS_ERROR;
dc8c34
+	int i = 0;
dc8c34
+
dc8c34
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
dc8c34
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
dc8c34
 
dc8c34
-		ber_printf(resp_bere, "{e}", response);
dc8c34
+	if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_GET_MAXCSN_OID) != 0 ||
dc8c34
+		   NULL == extop_payload || NULL == extop_payload->bv_val){
dc8c34
+		   /* something is wrong, error out */
dc8c34
+		   goto free_and_return;
dc8c34
+	}
dc8c34
+	/*
dc8c34
+	 *  Decode the payload
dc8c34
+	 */
dc8c34
+	if(decode_cleanruv_payload(extop_payload, &payload)){
dc8c34
+		   slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Get MaxCSN Task: failed to decode payload.  Aborting ext op\n");
dc8c34
+		   goto free_and_return;
dc8c34
+	}
dc8c34
+	rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
dc8c34
+	base_dn = ldap_utf8strtok_r(iter, ":", &iter);
dc8c34
+	/*
dc8c34
+	 *  Get the maxruv from the database tombstone entry
dc8c34
+	 */
dc8c34
+	filter = "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))";
dc8c34
+	attrs[0] = "nsds50ruv";
dc8c34
+	attrs[1] = NULL;
dc8c34
+	ridstr = slapi_ch_smprintf("{replica %d ldap", rid);
dc8c34
+
dc8c34
+	search_pb = slapi_pblock_new();
dc8c34
+	slapi_search_internal_set_pb(search_pb, base_dn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
+	slapi_search_internal_pb (search_pb);
dc8c34
+	slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res;;
dc8c34
+
dc8c34
+	if ( LDAP_SUCCESS == res ) {
dc8c34
+		slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
dc8c34
+		if (NULL == entries || entries[0] == NULL) {
dc8c34
+			/* Hmmm, no tombstpne!  Error out */
dc8c34
+		} else {
dc8c34
+			/* find the right ruv element, and find the maxcsn */
dc8c34
+			ruv_elements = slapi_entry_attr_get_charray(entries[0],attrs[0]);
dc8c34
+			for(i = 0; ruv_elements && ruv_elements[i] ; i++){
dc8c34
+				if(strstr(ruv_elements[i], ridstr)){
dc8c34
+					/* get the max csn */
dc8c34
+					ruv_part = ldap_utf8strtok_r(ruv_elements[i], " ", &iter);
dc8c34
+					for(part_count = 1; ruv_part && part_count < 5; part_count++){
dc8c34
+						ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
dc8c34
+					}
dc8c34
+					if(part_count == 5 && ruv_part){/* we have the maxcsn */
dc8c34
+						maxcsn = slapi_ch_strdup(ruv_part);
dc8c34
+						break;
dc8c34
+					}
dc8c34
+				}
dc8c34
+			}
dc8c34
+			slapi_ch_array_free(ruv_elements);
dc8c34
+		}
dc8c34
+	} else {
dc8c34
+		/* internal search failed */
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Get MaxCSN Task: internal search failed (%d)\n", res);
dc8c34
+	}
dc8c34
+	if(maxcsn == NULL){
dc8c34
+		maxcsn = slapi_ch_strdup(CLEANRUV_NO_MAXCSN);
dc8c34
+	}
dc8c34
+	/*
dc8c34
+	 *  Send the extended op response
dc8c34
+	 */
dc8c34
+	if ((resp_bere = der_alloc())){
dc8c34
+		ber_printf(resp_bere, "{s}", maxcsn);
dc8c34
 		ber_flatten(resp_bere, &resp_bval);
dc8c34
 		slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
dc8c34
 		slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
dc8c34
@@ -1760,10 +1874,96 @@ free_and_return:
dc8c34
 		rc = LDAP_OPERATIONS_ERROR;
dc8c34
 	}
dc8c34
 
dc8c34
+free_and_return:
dc8c34
+	slapi_free_search_results_internal(search_pb);
dc8c34
+	slapi_pblock_destroy(search_pb);
dc8c34
+	slapi_ch_free_string(&payload);
dc8c34
+	slapi_ch_free_string(&maxcsn);
dc8c34
+	slapi_ch_free_string(&ridstr);
dc8c34
+
dc8c34
 	return rc;
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
+ *  Search cn=config for the cleanallruv attributes (clean & abort)
dc8c34
+ */
dc8c34
+int
dc8c34
+multimaster_extop_cleanruv_check_status(Slapi_PBlock *pb)
dc8c34
+{
dc8c34
+	Slapi_PBlock *search_pb = NULL;
dc8c34
+	Slapi_Entry **entries = NULL;
dc8c34
+	struct berval *resp_bval = NULL;
dc8c34
+	struct berval *extop_payload;
dc8c34
+	BerElement *resp_bere = NULL;
dc8c34
+	char *response = NULL;
dc8c34
+	char *filter = NULL;
dc8c34
+	char *extop_oid;
dc8c34
+	int res = 0;
dc8c34
+	int rc = LDAP_OPERATIONS_ERROR;
dc8c34
+
dc8c34
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
dc8c34
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
dc8c34
+
dc8c34
+	if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_CHECK_STATUS_OID) != 0 ||
dc8c34
+		NULL == extop_payload || NULL == extop_payload->bv_val){
dc8c34
+		/* something is wrong, error out */
dc8c34
+		goto free_and_return;
dc8c34
+	}
dc8c34
+	/*
dc8c34
+	 *  Decode the payload - which should just be a filter
dc8c34
+	 */
dc8c34
+	if(decode_cleanruv_payload(extop_payload, &filter)){
dc8c34
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Check Status Task: failed to decode payload.  Aborting ext op\n");
dc8c34
+		goto free_and_return;
dc8c34
+	}
dc8c34
+
dc8c34
+	search_pb = slapi_pblock_new();
dc8c34
+	slapi_search_internal_set_pb(search_pb, "cn=config", LDAP_SCOPE_SUBTREE,
dc8c34
+		filter, NULL, 0, NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
+	slapi_search_internal_pb (search_pb);
dc8c34
+	slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res;;
dc8c34
+	if ( LDAP_SUCCESS == res ) {
dc8c34
+		slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
dc8c34
+		if (NULL == entries || entries[0] == NULL) {
dc8c34
+			/* cleaning task has finished, send repsonse */
dc8c34
+			response = CLEANRUV_FINISHED;
dc8c34
+		} else {
dc8c34
+			response = CLEANRUV_CLEANING;
dc8c34
+		}
dc8c34
+		/*
dc8c34
+		 *  Send the extended op response
dc8c34
+		 */
dc8c34
+		if ((resp_bere = der_alloc())){
dc8c34
+			ber_printf(resp_bere, "{s}", response);
dc8c34
+			ber_flatten(resp_bere, &resp_bval);
dc8c34
+			slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
dc8c34
+			slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
dc8c34
+			/* resp_bere */
dc8c34
+			if (NULL != resp_bere)
dc8c34
+			{
dc8c34
+				ber_free(resp_bere, 1);
dc8c34
+			}
dc8c34
+			/* resp_bval */
dc8c34
+			if (NULL != resp_bval)
dc8c34
+			{
dc8c34
+				ber_bvfree(resp_bval);
dc8c34
+			}
dc8c34
+			/* tell extendop code that we have already sent the result */
dc8c34
+			rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
dc8c34
+		}
dc8c34
+	}
dc8c34
+
dc8c34
+free_and_return:
dc8c34
+
dc8c34
+	slapi_free_search_results_internal(search_pb);
dc8c34
+	slapi_pblock_destroy(search_pb);
dc8c34
+	slapi_ch_free_string(&filter);
dc8c34
+
dc8c34
+	return rc;
dc8c34
+}
dc8c34
+
dc8c34
+
dc8c34
+/*
dc8c34
  * This plugin entry point is a noop entry
dc8c34
  * point. It's used when registering extops that
dc8c34
  * are only used as responses. We'll never receive
dc8c34
diff --git a/ldap/servers/plugins/replication/replutil.c b/ldap/servers/plugins/replication/replutil.c
dc8c34
index 5e8019c..d007f6c 100644
dc8c34
--- a/ldap/servers/plugins/replication/replutil.c
dc8c34
+++ b/ldap/servers/plugins/replication/replutil.c
dc8c34
@@ -765,33 +765,32 @@ repl_set_mtn_state_and_referrals(
dc8c34
 			ldap_free_urldesc(lud);
dc8c34
 	}
dc8c34
 
dc8c34
-        if (!referrals_to_set) { /* deleting referrals */
dc8c34
-            /* Set state before */
dc8c34
-			if (!chain_on_update) {
dc8c34
-				slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
dc8c34
+	if (!referrals_to_set) { /* deleting referrals */
dc8c34
+		/* Set state before */
dc8c34
+		if (!chain_on_update) {
dc8c34
+			slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
dc8c34
+		}
dc8c34
+		/* We should delete referral only if we want to set the
dc8c34
+		   replica database in backend state mode */
dc8c34
+		/* if chain on update mode, go ahead and set the referrals anyway */
dc8c34
+		if (strcasecmp(mtn_state, STATE_BACKEND) == 0 || chain_on_update) {
dc8c34
+			rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
dc8c34
+			if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
dc8c34
+				/* we will get no such attribute (16) if we try to set the referrals to NULL if
dc8c34
+				   there are no referrals - not an error */
dc8c34
+				rc = LDAP_SUCCESS;
dc8c34
 			}
dc8c34
-            /* We should delete referral only if we want to set the 
dc8c34
-               replica database in backend state mode */
dc8c34
-			/* if chain on update mode, go ahead and set the referrals anyway */
dc8c34
-            if (strcasecmp(mtn_state, STATE_BACKEND) == 0 || chain_on_update) {
dc8c34
-                rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
dc8c34
-                if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
dc8c34
-                    /* we will get no such attribute (16) if we try to set the referrals to NULL if
dc8c34
-                       there are no referrals - not an error */
dc8c34
-                    rc = LDAP_SUCCESS;
dc8c34
-                }
dc8c34
-            }
dc8c34
-        } else { /* Replacing */
dc8c34
-            rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
dc8c34
-            if (rc == LDAP_SUCCESS && !chain_on_update){
dc8c34
-                slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
dc8c34
-            }
dc8c34
-        }
dc8c34
+		}
dc8c34
+	} else { /* Replacing */
dc8c34
+		rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
dc8c34
+		if (rc == LDAP_SUCCESS && !chain_on_update){
dc8c34
+			slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
dc8c34
+		}
dc8c34
+	}
dc8c34
 
dc8c34
-        if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) {
dc8c34
+	if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) {
dc8c34
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "repl_set_mtn_referrals: could "
dc8c34
-						"not set referrals for replica %s: %d\n",
dc8c34
-						slapi_sdn_get_dn(repl_root_sdn), rc);
dc8c34
+			"not set referrals for replica %s: %d\n", slapi_sdn_get_dn(repl_root_sdn), rc);
dc8c34
 	}
dc8c34
 
dc8c34
 	charray_free(referrals_to_set);
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
index 6d2e6f6..5c9585f 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
dc8c34
@@ -71,6 +71,11 @@ void modify_init(modify_context *mc,struct backentry *old_entry)
dc8c34
 
dc8c34
 int modify_apply_mods(modify_context *mc, Slapi_Mods *smods)
dc8c34
 {
dc8c34
+	return modify_apply_mods_ignore_error(mc, smods, -1);
dc8c34
+}
dc8c34
+
dc8c34
+int modify_apply_mods_ignore_error(modify_context *mc, Slapi_Mods *smods, int error)
dc8c34
+{
dc8c34
 	int ret = 0;
dc8c34
 	/* Make a copy of the entry */
dc8c34
 	PR_ASSERT(mc->old_entry != NULL);
dc8c34
@@ -78,7 +83,7 @@ int modify_apply_mods(modify_context *mc, Slapi_Mods *smods)
dc8c34
 	mc->new_entry = backentry_dup(mc->old_entry);
dc8c34
 	PR_ASSERT(smods!=NULL);
dc8c34
 	if ( mods_have_effect (mc->new_entry->ep_entry, smods) ) {
dc8c34
-		ret = entry_apply_mods( mc->new_entry->ep_entry, slapi_mods_get_ldapmods_byref(smods));
dc8c34
+		ret = entry_apply_mods_ignore_error( mc->new_entry->ep_entry, slapi_mods_get_ldapmods_byref(smods), error);
dc8c34
 	}
dc8c34
 	mc->smods= smods;
dc8c34
 	return ret;
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
index a56069b..fd62df9 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/misc.c
dc8c34
@@ -444,7 +444,7 @@ ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
dc8c34
 
dc8c34
     modify_init( mc, bentry );
dc8c34
 
dc8c34
-    if (modify_apply_mods( mc, smods )) {
dc8c34
+    if (modify_apply_mods_ignore_error( mc, smods, LDAP_TYPE_OR_VALUE_EXISTS )) {
dc8c34
         LDAPDebug( LDAP_DEBUG_ANY, "Error: ldbm_txn_ruv_modify_context failed to apply updates to RUV entry\n",
dc8c34
             0, 0, 0 );
dc8c34
         rc = -1;
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
index 48b3164..a7fb06d 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
dc8c34
@@ -347,6 +347,7 @@ void modify_init(modify_context *mc,struct backentry *old_entry);
dc8c34
 int modify_apply_mods(modify_context *mc, Slapi_Mods *smods);
dc8c34
 int modify_term(modify_context *mc,backend *be);
dc8c34
 int modify_switch_entries(modify_context *mc,backend *be);
dc8c34
+int modify_apply_mods_ignore_error(modify_context *mc, Slapi_Mods *smods, int error);
dc8c34
 
dc8c34
 /*
dc8c34
  * add.c
dc8c34
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
dc8c34
index 6339a6f..58a9d51 100644
dc8c34
--- a/ldap/servers/slapd/entry.c
dc8c34
+++ b/ldap/servers/slapd/entry.c
dc8c34
@@ -3259,6 +3259,12 @@ int slapi_entry_apply_mod( Slapi_Entry *e, LDAPMod *mod )
dc8c34
 int
dc8c34
 entry_apply_mods( Slapi_Entry *e, LDAPMod **mods )
dc8c34
 {
dc8c34
+	return entry_apply_mods_ignore_error(e, mods, -1);
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+entry_apply_mods_ignore_error( Slapi_Entry *e, LDAPMod **mods, int ignore_error )
dc8c34
+{
dc8c34
 	int	err;
dc8c34
 	LDAPMod **mp = NULL;
dc8c34
 
dc8c34
@@ -3268,7 +3274,9 @@ entry_apply_mods( Slapi_Entry *e, LDAPMod **mods )
dc8c34
 	for ( mp = mods; mp && *mp; mp++ )
dc8c34
 	{
dc8c34
 		err = entry_apply_mod( e, *mp );
dc8c34
-		if ( err != LDAP_SUCCESS ) {
dc8c34
+		if(err == ignore_error){
dc8c34
+			(*mp)->mod_op = LDAP_MOD_IGNORE;
dc8c34
+		} else if ( err != LDAP_SUCCESS ) {
dc8c34
 			break;
dc8c34
 		}
dc8c34
 	}
dc8c34
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
dc8c34
index f7b4d04..ddeac62 100644
dc8c34
--- a/ldap/servers/slapd/slapi-private.h
dc8c34
+++ b/ldap/servers/slapd/slapi-private.h
dc8c34
@@ -331,7 +331,7 @@ int entry_next_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a);
dc8c34
 /* entry.c */
dc8c34
 int entry_apply_mods( Slapi_Entry *e, LDAPMod **mods );
dc8c34
 int is_type_protected(const char *type);
dc8c34
-
dc8c34
+int entry_apply_mods_ignore_error( Slapi_Entry *e, LDAPMod **mods, int ignore_error );
dc8c34
 int slapi_entries_diff(Slapi_Entry **old_entries, Slapi_Entry **new_entries, int testall, const char *logging_prestr, const int force_update, void *plg_id);
dc8c34
 
dc8c34
 /* entrywsi.c */
dc8c34
-- 
dc8c34
1.7.11.7
dc8c34