[389-commits] Branch '389-ds-base-1.2.11' - 10 commits - ldap/admin ldap/schema ldap/servers Makefile.am Makefile.in

Richard Allen Megginson rmeggins at fedoraproject.org
Fri Aug 3 19:33:27 UTC 2012


 Makefile.am                                              |    1 
 Makefile.in                                              |    1 
 ldap/admin/src/scripts/template-cleanallruv.pl.in        |  186 +
 ldap/schema/01core389.ldif                               |   17 
 ldap/servers/plugins/dna/dna.c                           |   12 
 ldap/servers/plugins/linkedattrs/fixup_task.c            |    2 
 ldap/servers/plugins/linkedattrs/linked_attrs.h          |    2 
 ldap/servers/plugins/memberof/memberof.c                 |    2 
 ldap/servers/plugins/memberof/memberof.h                 |    2 
 ldap/servers/plugins/replication/cl5_api.c               |   75 
 ldap/servers/plugins/replication/cl5_api.h               |    9 
 ldap/servers/plugins/replication/cl5_clcache.c           |   16 
 ldap/servers/plugins/replication/repl5.h                 |   58 
 ldap/servers/plugins/replication/repl5_agmt.c            |  171 -
 ldap/servers/plugins/replication/repl5_agmtlist.c        |   13 
 ldap/servers/plugins/replication/repl5_connection.c      |   13 
 ldap/servers/plugins/replication/repl5_inc_protocol.c    |   21 
 ldap/servers/plugins/replication/repl5_init.c            |   46 
 ldap/servers/plugins/replication/repl5_plugins.c         |   18 
 ldap/servers/plugins/replication/repl5_replica.c         |  497 ++-
 ldap/servers/plugins/replication/repl5_replica_config.c  | 2238 +++++++++++----
 ldap/servers/plugins/replication/repl5_ruv.c             |   58 
 ldap/servers/plugins/replication/repl5_ruv.h             |    1 
 ldap/servers/plugins/replication/repl_extop.c            |  448 +--
 ldap/servers/plugins/replication/repl_globals.c          |    5 
 ldap/servers/plugins/replication/windows_private.c       | 1270 ++++++--
 ldap/servers/plugins/replication/windows_protocol_util.c |   29 
 ldap/servers/plugins/replication/windowsrepl.h           |    1 
 ldap/servers/plugins/replication/winsync-plugin.h        |  653 ----
 ldap/servers/plugins/rootdn_access/rootdn_access.c       |   32 
 ldap/servers/plugins/uiduniq/uid.c                       |    3 
 ldap/servers/plugins/usn/usn_cleanup.c                   |    2 
 ldap/servers/slapd/apibroker.c                           |   58 
 ldap/servers/slapd/back-ldbm/cache.c                     |   24 
 ldap/servers/slapd/back-ldbm/dblayer.c                   |    2 
 ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c             |    6 
 ldap/servers/slapd/back-ldbm/ldbm_search.c               |    2 
 ldap/servers/slapd/libglobs.c                            |   63 
 ldap/servers/slapd/log.c                                 |   27 
 ldap/servers/slapd/slapi-plugin.h                        |   48 
 ldap/servers/slapd/task.c                                |   56 
 41 files changed, 4161 insertions(+), 2027 deletions(-)

New commits:
commit fb1e89cb0117a44082cebb6289735e740860c783
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Thu Aug 2 16:48:11 2012 -0600

    Ticket #425 - support multiple winsync plugins
    
    https://fedorahosted.org/389/ticket/425
    Resolves: Ticket #425
    Bug Description: support multiple winsync plugins
    Reviewed by: nkinder (Thanks!)
    Branch: 389-ds-base-1.2.11
    Fix Description: Instead of a single WinsyncAPI pointer, use a CList to
    store a list of APIs.  Added API version 3 - the new function is a
    precedence callback so the API can report back the plugin precedence to
    order multiple winsync plugins.  Since each API may have a different
    cookie per agreement, changed the cookie to be a list of cookies indexed
    by the API pointer.  The old slapi_apib interface stored multiple APIs
    per GUID, but did not allow plugins to retrieve them.  I added another
    slapi_apib function which allows the plugin to retrieve all of the APIs
    for a given GUID.
    I also move the test winsync code from the public header into the
    windows_private.c code and compiled it by default.  This will allow us to
    easily enable the plugin for testing, and also exercises the compiler in
    case we make an incompatible change to the public API.
    Platforms tested: RHEL6 x86_64
    Flag Day: Yes - public header file change
    Doc impact: Yes - document the new behavior and precedence

diff --git a/ldap/servers/plugins/replication/windows_private.c b/ldap/servers/plugins/replication/windows_private.c
index 72cb721..85b585a 100644
--- a/ldap/servers/plugins/replication/windows_private.c
+++ b/ldap/servers/plugins/replication/windows_private.c
@@ -258,6 +258,8 @@ void windows_agreement_delete(Repl_Agmt *ra)
 	winsync_plugin_call_destroy_agmt_cb(ra, dp->directory_subtree,
 										dp->windows_subtree);
 
+	windows_plugin_cleanup_agmt(ra);
+
 	slapi_sdn_free(&dp->directory_subtree);
 	slapi_sdn_free(&dp->windows_subtree);
 	slapi_filter_free(dp->directory_filter, 1);
@@ -1017,78 +1019,235 @@ windows_private_set_sync_interval(Repl_Agmt *ra, char *str)
 	LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_set_sync_interval\n" );
 }
 
-/* an array of function pointers */
-static void **_WinSyncAPI = NULL;
-static int maxapiidx = WINSYNC_PLUGIN_VERSION_1_END;
-#define DECL_WINSYNC_API_FUNC(idx,thetype,thefunc) \
-    thetype thefunc = (_WinSyncAPI && (idx <= maxapiidx) && _WinSyncAPI[idx]) ? \
-        (thetype)_WinSyncAPI[idx] : NULL;
+static PRCallOnceType winsync_callOnce = {0,0};
 
-void
-windows_plugin_init(Repl_Agmt *ra)
+struct winsync_plugin {
+    struct winsync_plugin *next; /* see PRCList - declare here to avoid lots of casting */
+    struct winsync_plugin *prev; /* see PRCList - declare here to avoid lots of casting */
+    void **api; /* the api - array of function pointers */
+    int maxapi; /* the max index i.e. the api version */
+    int precedence; /* lower number == higher precedence */
+};
+static struct winsync_plugin winsync_plugin_list;
+
+#define DECL_WINSYNC_API_IDX_FUNC(theapi,idx,maxidx,thetype,thefunc)    \
+    thetype thefunc = (theapi && (idx <= maxidx) && theapi[idx]) ? \
+        (thetype)theapi[idx] : NULL;
+
+#define WINSYNC_PLUGIN_CALL_PLUGINS_BEGIN(idx,thetype,thefunc) \
+    struct winsync_plugin *elem; \
+    for (elem = PR_LIST_HEAD(&winsync_plugin_list); \
+         elem && (elem != &winsync_plugin_list); \
+         elem = PR_NEXT_LINK(elem)) { \
+        DECL_WINSYNC_API_IDX_FUNC(elem->api,idx,elem->maxapi,thetype,thefunc); \
+        if (thefunc) {
+
+#define WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(idx,thetype,thefunc) \
+    WINSYNC_PLUGIN_CALL_PLUGINS_BEGIN(idx,thetype,thefunc) \
+    void *cookie = winsync_plugin_cookie_find(ra, elem->api);
+
+#define WINSYNC_PLUGIN_CALL_PLUGINS_END } /* this one matches if thefunc */ } /* this one matches the for loop */
+
+/* this structure is per agreement - to store the cookie per agreement
+   for each winsync plugin */
+struct winsync_plugin_cookie {
+    struct winsync_plugin_cookie *next; /* see PRCList - declare here to avoid lots of casting */
+    struct winsync_plugin_cookie *prev; /* see PRCList - declare here to avoid lots of casting */
+    void **api; /* the api - array of function pointers */
+    void *cookie; /* plugin data */
+};
+
+static struct winsync_plugin *
+new_winsync_plugin(void **theapi, int maxapi, int precedence)
 {
-    void *cookie = NULL;
-    winsync_plugin_init_cb initfunc = NULL;
-
-	LDAPDebug0Args( LDAP_DEBUG_PLUGIN, "--> windows_plugin_init_start -- begin\n");
-
-    /* if the function pointer array is null, get the functions - we will
-       call init once per replication agreement, but will only grab the
-       api once */
-    if(NULL == _WinSyncAPI) {
-        if (slapi_apib_get_interface(WINSYNC_v2_0_GUID, &_WinSyncAPI) ||
-            (NULL == _WinSyncAPI))
-        {
-            LDAPDebug1Arg( LDAP_DEBUG_PLUGIN,
-                           "<-- windows_plugin_init_start -- no windows plugin API registered for GUID [%s] -- end\n",
-                           WINSYNC_v2_0_GUID);
-        } else if (_WinSyncAPI) {
-            LDAPDebug1Arg( LDAP_DEBUG_PLUGIN,
-                           "<-- windows_plugin_init_start -- found windows plugin API registered for GUID [%s] -- end\n",
-                           WINSYNC_v2_0_GUID);
-            maxapiidx = WINSYNC_PLUGIN_VERSION_2_END;
+    struct winsync_plugin *wpi = (struct winsync_plugin *)slapi_ch_calloc(1, sizeof(struct winsync_plugin));
+    wpi->api = theapi;
+    wpi->maxapi = maxapi;
+    wpi->precedence = precedence;
+    return wpi;
+}
+
+static struct winsync_plugin *
+windows_plugin_find(void **theapi)
+{
+    struct winsync_plugin *elem = PR_LIST_HEAD(&winsync_plugin_list);
+    while (elem && (elem != &winsync_plugin_list)) {
+        if (theapi == elem->api) {
+            return elem;
         }
+        elem = PR_NEXT_LINK(elem);
     }
+    return NULL;
+}
+
+/* returns 0 for success - 1 means already added - -1 means some error */
+static int
+windows_plugin_add(void **theapi, int maxapi)
+{
+    int precedence = WINSYNC_PLUGIN_DEFAULT_PRECEDENCE;
+    DECL_WINSYNC_API_IDX_FUNC(theapi,WINSYNC_PLUGIN_PRECEDENCE_CB,maxapi,winsync_plugin_precedence_cb,thefunc);
 
-    if (NULL == _WinSyncAPI) { /* no v2 interface - look for v1 */
-        if (slapi_apib_get_interface(WINSYNC_v1_0_GUID, &_WinSyncAPI) ||
-            (NULL == _WinSyncAPI))
-        {
-            LDAPDebug1Arg( LDAP_DEBUG_PLUGIN,
-                           "<-- windows_plugin_init_start -- no windows plugin API registered for GUID [%s] -- end\n",
-                           WINSYNC_v1_0_GUID);
-            return;
+    if (thefunc) {
+        /* supports precedence */
+        precedence = (*thefunc)();
+    }
+    if (PR_CLIST_IS_EMPTY(&winsync_plugin_list)) {
+        struct winsync_plugin *wpi = new_winsync_plugin(theapi, maxapi, precedence);
+        PR_INSERT_LINK(wpi, &winsync_plugin_list);
+        return 0;
+    } else if (windows_plugin_find(theapi)) {
+        return 1; /* already in list */
+    } else {
+        struct winsync_plugin *wpi = new_winsync_plugin(theapi, maxapi, precedence);
+        struct winsync_plugin *elem = PR_LIST_HEAD(&winsync_plugin_list);
+        while (elem && (elem != &winsync_plugin_list)) {
+            if (precedence < elem->precedence) {
+                PR_INSERT_BEFORE(wpi, elem);
+                break;
+            }
+            elem = PR_NEXT_LINK(elem);
+        }
+        if (elem == &winsync_plugin_list) {
+            /* just add to end of list */
+            PR_INSERT_BEFORE(wpi, elem);
+        }
+        return 0;
+    }
+    return -1;
+}
+
+static PRStatus
+windows_plugin_callonce(void)
+{
+    char *guids[] = {WINSYNC_v3_0_GUID, WINSYNC_v2_0_GUID, WINSYNC_v1_0_GUID, NULL};
+    int maxapis[] = {WINSYNC_PLUGIN_VERSION_3_END, WINSYNC_PLUGIN_VERSION_2_END,
+                     WINSYNC_PLUGIN_VERSION_1_END, 0};
+    int ii;
+
+    PR_INIT_CLIST(&winsync_plugin_list);
+    /* loop through all of the registered winsync plugins - look for them in reverse
+       version order (e.g. look for v3 first) - if there are no plugins registered
+       for the given version, or we have already registered all plugins for a given
+       version, just go to the next lowest version */
+    for (ii = 0; guids[ii]; ++ii) {
+        char *guid = guids[ii];
+        int maxapi = maxapis[ii];
+        void ***theapis = NULL;
+        
+        if (slapi_apib_get_interface_all(guid, &theapis) || (NULL == theapis)) {
+            LDAPDebug1Arg(LDAP_DEBUG_PLUGIN,
+                          "<-- windows_plugin_callonce -- no more windows plugin APIs registered "
+                          "for GUID [%s] -- end\n",
+                          guid);
         } else {
-            LDAPDebug1Arg( LDAP_DEBUG_PLUGIN,
-                           "<-- windows_plugin_init_start -- found windows plugin API registered for GUID [%s] -- end\n",
-                           WINSYNC_v1_0_GUID);
+            int idx;
+            for (idx = 0; theapis && theapis[idx]; ++idx) {
+                if (windows_plugin_add(theapis[idx], maxapi)) {
+                    LDAPDebug(LDAP_DEBUG_PLUGIN,
+                              "<-- windows_plugin_callonce -- already added windows plugin API "
+                              "[%d][0x%p] for GUID [%s] -- end\n",
+                              idx, theapis[idx], guid);
+                }
+            }
         }
-	}
+        slapi_ch_free((void **)&theapis);
+    }
+    return PR_SUCCESS;
+}
+
+static struct winsync_plugin_cookie *
+new_winsync_plugin_cookie(void **theapi, void *cookie)
+{
+    struct winsync_plugin_cookie *wpc = (struct winsync_plugin_cookie *)slapi_ch_calloc(1, sizeof(struct winsync_plugin_cookie));
+    wpc->api = theapi;
+    wpc->cookie = cookie;
+    return wpc;
+}
+
+static void *
+winsync_plugin_cookie_find(const Repl_Agmt *ra, void **theapi)
+{
+    if (ra) {
+        struct winsync_plugin_cookie *list = (struct winsync_plugin_cookie *)windows_private_get_api_cookie(ra);
+        if (list) {
+            struct winsync_plugin_cookie *elem = PR_LIST_HEAD(list);
+            while (elem && (elem != list)) {
+                if (theapi == elem->api) {
+                    return elem->cookie;
+                }
+                elem = PR_NEXT_LINK(elem);
+            }
+        }
+    }
+    return NULL;
+}
+
+static void
+winsync_plugin_cookie_add(struct winsync_plugin_cookie **list, void **theapi, void *cookie)
+{
+    struct winsync_plugin_cookie *elem = NULL;
+    if (!*list) {
+        *list = new_winsync_plugin_cookie(NULL, NULL);
+        PR_INIT_CLIST(*list);
+    }
+    elem = new_winsync_plugin_cookie(theapi, cookie);
+    PR_INSERT_BEFORE(elem, *list);
+    return;
+}
 
-    initfunc = (winsync_plugin_init_cb)_WinSyncAPI[WINSYNC_PLUGIN_INIT_CB];
-    if (initfunc) {
-        cookie = (*initfunc)(windows_private_get_directory_subtree(ra),
-                             windows_private_get_windows_subtree(ra));
+void
+windows_plugin_init(Repl_Agmt *ra)
+{
+    struct winsync_plugin_cookie *list = NULL;
+    void *cookie = NULL;
+    PRStatus rv;
+
+    LDAPDebug0Args( LDAP_DEBUG_PLUGIN, "--> windows_plugin_init_start -- begin\n");
+
+    rv = PR_CallOnce(&winsync_callOnce, windows_plugin_callonce);
+
+    /* call each plugin init function in turn - store the returned cookie
+       indexed by the api */
+    {
+        WINSYNC_PLUGIN_CALL_PLUGINS_BEGIN(WINSYNC_PLUGIN_INIT_CB,winsync_plugin_init_cb,thefunc)
+            cookie = (*thefunc)(windows_private_get_directory_subtree(ra),
+                                windows_private_get_windows_subtree(ra));
+            if (cookie) {
+                winsync_plugin_cookie_add(&list, elem->api, cookie);
+            }
+        WINSYNC_PLUGIN_CALL_PLUGINS_END
     }
-    windows_private_set_api_cookie(ra, cookie);
+       
+    windows_private_set_api_cookie(ra, list);
 
-	LDAPDebug0Args( LDAP_DEBUG_PLUGIN, "<-- windows_plugin_init_start -- end\n");
+    LDAPDebug0Args( LDAP_DEBUG_PLUGIN, "<-- windows_plugin_init_start -- end\n");
     return;
 }
 
 void
-winsync_plugin_call_dirsync_search_params_cb(const Repl_Agmt *ra, const char *agmt_dn,
-                                             char **base, int *scope, char **filter,
-                                             char ***attrs, LDAPControl ***serverctrls)
+windows_plugin_cleanup_agmt(Repl_Agmt *ra)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB,winsync_search_params_cb,thefunc);
+    struct winsync_plugin_cookie *list = (struct winsync_plugin_cookie *)windows_private_get_api_cookie(ra);
+    struct winsync_plugin_cookie *elem = NULL;
 
-    if (!thefunc) {
-        return;
+    while (list && !PR_CLIST_IS_EMPTY(list)) {
+        elem = PR_LIST_HEAD(list);
+        PR_REMOVE_LINK(elem);
+        slapi_ch_free((void **)&elem);
     }
+    slapi_ch_free((void **)&list);
+    windows_private_set_api_cookie(ra, NULL);
+    return;
+}
 
-    (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter,
-               attrs, serverctrls);
+void
+winsync_plugin_call_dirsync_search_params_cb(const Repl_Agmt *ra, const char *agmt_dn,
+                                             char **base, int *scope, char **filter,
+                                             char ***attrs, LDAPControl ***serverctrls)
+{
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB,winsync_search_params_cb,thefunc)
+        (*thefunc)(cookie, agmt_dn, base, scope, filter, attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1098,14 +1257,9 @@ winsync_plugin_call_pre_ad_search_cb(const Repl_Agmt *ra, const char *agmt_dn,
                                      char **base, int *scope, char **filter,
                                      char ***attrs, LDAPControl ***serverctrls)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_SEARCH_CB,winsync_search_params_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter,
-               attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_SEARCH_CB,winsync_search_params_cb,thefunc)
+        (*thefunc)(cookie, agmt_dn, base, scope, filter, attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1115,14 +1269,9 @@ winsync_plugin_call_pre_ds_search_entry_cb(const Repl_Agmt *ra, const char *agmt
                                            char **base, int *scope, char **filter,
                                            char ***attrs, LDAPControl ***serverctrls)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB,winsync_search_params_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter,
-               attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB,winsync_search_params_cb,thefunc)
+        (*thefunc)(cookie, agmt_dn, base, scope, filter, attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1132,14 +1281,9 @@ winsync_plugin_call_pre_ds_search_all_cb(const Repl_Agmt *ra, const char *agmt_d
                                          char **base, int *scope, char **filter,
                                          char ***attrs, LDAPControl ***serverctrls)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB,winsync_search_params_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter,
-               attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB,winsync_search_params_cb,thefunc)
+        (*thefunc)(cookie, agmt_dn, base, scope, filter, attrs, serverctrls);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1149,14 +1293,9 @@ winsync_plugin_call_pre_ad_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *r
                                        Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                        Slapi_Mods *smods, int *do_modify)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_MOD_USER_CB,winsync_pre_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_MOD_USER_CB,winsync_pre_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1166,14 +1305,9 @@ winsync_plugin_call_pre_ad_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry *
                                         Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                         Slapi_Mods *smods, int *do_modify)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_CB,winsync_pre_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_CB,winsync_pre_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1183,14 +1317,9 @@ winsync_plugin_call_pre_ds_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *r
                                        Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                        Slapi_Mods *smods, int *do_modify)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_DS_MOD_USER_CB,winsync_pre_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_DS_MOD_USER_CB,winsync_pre_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1200,14 +1329,9 @@ winsync_plugin_call_pre_ds_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry *
                                         Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                         Slapi_Mods *smods, int *do_modify)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_DS_MOD_GROUP_CB,winsync_pre_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_DS_MOD_GROUP_CB,winsync_pre_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, do_modify);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1216,14 +1340,9 @@ void
 winsync_plugin_call_pre_ds_add_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry,
                                        Slapi_Entry *ad_entry, Slapi_Entry *ds_entry)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_DS_ADD_USER_CB,winsync_pre_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_DS_ADD_USER_CB,winsync_pre_add_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1232,14 +1351,9 @@ void
 winsync_plugin_call_pre_ds_add_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry,
                                         Slapi_Entry *ad_entry, Slapi_Entry *ds_entry)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_DS_ADD_GROUP_CB,winsync_pre_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_DS_ADD_GROUP_CB,winsync_pre_add_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1249,14 +1363,9 @@ winsync_plugin_call_get_new_ds_user_dn_cb(const Repl_Agmt *ra, const Slapi_Entry
                                           Slapi_Entry *ad_entry, char **new_dn_string,
                                           const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_GET_NEW_DS_USER_DN_CB,winsync_get_new_dn_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               new_dn_string, ds_suffix, ad_suffix);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_GET_NEW_DS_USER_DN_CB,winsync_get_new_dn_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, new_dn_string, ds_suffix, ad_suffix);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1266,14 +1375,9 @@ winsync_plugin_call_get_new_ds_group_dn_cb(const Repl_Agmt *ra, const Slapi_Entr
                                            Slapi_Entry *ad_entry, char **new_dn_string,
                                            const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_GET_NEW_DS_GROUP_DN_CB,winsync_get_new_dn_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               new_dn_string, ds_suffix, ad_suffix);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_GET_NEW_DS_GROUP_DN_CB,winsync_get_new_dn_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, new_dn_string, ds_suffix, ad_suffix);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1285,14 +1389,9 @@ winsync_plugin_call_pre_ad_mod_user_mods_cb(const Repl_Agmt *ra, const Slapi_Ent
                                             LDAPMod * const *origmods,
                                             Slapi_DN *remote_dn, LDAPMod ***modstosend)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_MOD_USER_MODS_CB,winsync_pre_ad_mod_mods_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, local_dn,
-               ds_entry, origmods, remote_dn, modstosend);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_MOD_USER_MODS_CB,winsync_pre_ad_mod_mods_cb,thefunc)
+        (*thefunc)(cookie, rawentry, local_dn, ds_entry, origmods, remote_dn, modstosend);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1304,14 +1403,9 @@ winsync_plugin_call_pre_ad_mod_group_mods_cb(const Repl_Agmt *ra, const Slapi_En
                                              LDAPMod * const *origmods,
                                              Slapi_DN *remote_dn, LDAPMod ***modstosend)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_MODS_CB,winsync_pre_ad_mod_mods_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, local_dn,
-               ds_entry, origmods, remote_dn, modstosend);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_MODS_CB,winsync_pre_ad_mod_mods_cb,thefunc)
+        (*thefunc)(cookie, rawentry, local_dn, ds_entry, origmods, remote_dn, modstosend);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1320,26 +1414,22 @@ int
 winsync_plugin_call_can_add_entry_to_ad_cb(const Repl_Agmt *ra, const Slapi_Entry *local_entry,
                                            const Slapi_DN *remote_dn)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_CAN_ADD_ENTRY_TO_AD_CB,winsync_can_add_to_ad_cb,thefunc);
-
-    if (!thefunc) {
-        return 1; /* default is entry can be added to AD */
-    }
-
-    return (*thefunc)(windows_private_get_api_cookie(ra), local_entry, remote_dn);
+    int canadd = 1;
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_CAN_ADD_ENTRY_TO_AD_CB,winsync_can_add_to_ad_cb,thefunc)
+        if (canadd) {
+            canadd = (*thefunc)(cookie, local_entry, remote_dn);
+        }
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
+    return canadd;
 }
 
 void
 winsync_plugin_call_begin_update_cb(const Repl_Agmt *ra, const Slapi_DN *ds_subtree,
                                     const Slapi_DN *ad_subtree, int is_total)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_BEGIN_UPDATE_CB,winsync_plugin_update_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), ds_subtree, ad_subtree, is_total);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_BEGIN_UPDATE_CB,winsync_plugin_update_cb,thefunc)
+        (*thefunc)(cookie, ds_subtree, ad_subtree, is_total);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1348,13 +1438,9 @@ void
 winsync_plugin_call_end_update_cb(const Repl_Agmt *ra, const Slapi_DN *ds_subtree,
                                   const Slapi_DN *ad_subtree, int is_total)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_END_UPDATE_CB,winsync_plugin_update_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), ds_subtree, ad_subtree, is_total);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_END_UPDATE_CB,winsync_plugin_update_cb,thefunc)
+        (*thefunc)(cookie, ds_subtree, ad_subtree, is_total);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1364,11 +1450,9 @@ winsync_plugin_call_destroy_agmt_cb(const Repl_Agmt *ra,
                                     const Slapi_DN *ds_subtree,
                                     const Slapi_DN *ad_subtree)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_DESTROY_AGMT_CB,winsync_plugin_destroy_agmt_cb,thefunc);
-
-    if (thefunc) {
-        (*thefunc)(windows_private_get_api_cookie(ra), ds_subtree, ad_subtree);
-    }
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_DESTROY_AGMT_CB,winsync_plugin_destroy_agmt_cb,thefunc)
+        (*thefunc)(cookie, ds_subtree, ad_subtree);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1378,14 +1462,9 @@ winsync_plugin_call_post_ad_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *
                                         Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                         Slapi_Mods *smods, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_AD_MOD_USER_CB,winsync_post_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_AD_MOD_USER_CB,winsync_post_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1395,14 +1474,9 @@ winsync_plugin_call_post_ad_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry
                                          Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                          Slapi_Mods *smods, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_AD_MOD_GROUP_CB,winsync_post_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_AD_MOD_GROUP_CB,winsync_post_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1412,14 +1486,9 @@ winsync_plugin_call_post_ds_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *
                                         Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                         Slapi_Mods *smods, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_DS_MOD_USER_CB,winsync_post_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_DS_MOD_USER_CB,winsync_post_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1429,14 +1498,9 @@ winsync_plugin_call_post_ds_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry
                                          Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
                                          Slapi_Mods *smods, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_DS_MOD_GROUP_CB,winsync_post_mod_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_DS_MOD_GROUP_CB,winsync_post_mod_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, smods, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1445,14 +1509,9 @@ void
 winsync_plugin_call_post_ds_add_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry,
                                         Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_DS_ADD_USER_CB,winsync_post_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_DS_ADD_USER_CB,winsync_post_add_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1461,14 +1520,9 @@ void
 winsync_plugin_call_post_ds_add_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry,
                                          Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_DS_ADD_GROUP_CB,winsync_post_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry,
-               ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_DS_ADD_GROUP_CB,winsync_post_add_cb,thefunc)
+        (*thefunc)(cookie, rawentry, ad_entry, ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1477,13 +1531,9 @@ void
 winsync_plugin_call_pre_ad_add_user_cb(const Repl_Agmt *ra, Slapi_Entry *ad_entry,
                                        Slapi_Entry *ds_entry)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_ADD_USER_CB,winsync_pre_ad_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), ad_entry, ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_ADD_USER_CB,winsync_pre_ad_add_cb,thefunc)
+        (*thefunc)(cookie, ad_entry, ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1492,13 +1542,9 @@ void
 winsync_plugin_call_pre_ad_add_group_cb(const Repl_Agmt *ra, Slapi_Entry *ad_entry,
                                         Slapi_Entry *ds_entry)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_PRE_AD_ADD_GROUP_CB,winsync_pre_ad_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), ad_entry, ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_PRE_AD_ADD_GROUP_CB,winsync_pre_ad_add_cb,thefunc)
+        (*thefunc)(cookie, ad_entry, ds_entry);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1507,13 +1553,9 @@ void
 winsync_plugin_call_post_ad_add_user_cb(const Repl_Agmt *ra, Slapi_Entry *ad_entry,
                                         Slapi_Entry *ds_entry, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_AD_ADD_USER_CB,winsync_post_ad_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), ad_entry, ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_AD_ADD_USER_CB,winsync_post_ad_add_cb,thefunc)
+        (*thefunc)(cookie, ad_entry, ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1522,13 +1564,9 @@ void
 winsync_plugin_call_post_ad_add_group_cb(const Repl_Agmt *ra, Slapi_Entry *ad_entry,
                                          Slapi_Entry *ds_entry, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_AD_ADD_GROUP_CB,winsync_post_ad_add_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), ad_entry, ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_AD_ADD_GROUP_CB,winsync_post_ad_add_cb,thefunc)
+        (*thefunc)(cookie, ad_entry, ds_entry, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1540,14 +1578,9 @@ winsync_plugin_call_post_ad_mod_user_mods_cb(const Repl_Agmt *ra, const Slapi_En
                                              LDAPMod * const *origmods,
                                              Slapi_DN *remote_dn, LDAPMod **modstosend, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_AD_MOD_USER_MODS_CB,winsync_post_ad_mod_mods_cb,thefunc);
-
-    if (!thefunc) {
-        return;
-    }
-
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, local_dn,
-               ds_entry, origmods, remote_dn, modstosend, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_AD_MOD_USER_MODS_CB,winsync_post_ad_mod_mods_cb,thefunc)
+        (*thefunc)(cookie, rawentry, local_dn, ds_entry, origmods, remote_dn, modstosend, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
 
     return;
 }
@@ -1559,18 +1592,711 @@ winsync_plugin_call_post_ad_mod_group_mods_cb(const Repl_Agmt *ra, const Slapi_E
                                               LDAPMod * const *origmods,
                                               Slapi_DN *remote_dn, LDAPMod **modstosend, int *result)
 {
-    DECL_WINSYNC_API_FUNC(WINSYNC_PLUGIN_POST_AD_MOD_GROUP_MODS_CB,winsync_post_ad_mod_mods_cb,thefunc);
+    WINSYNC_PLUGIN_CALL_PLUGINS_COOKIE_BEGIN(WINSYNC_PLUGIN_POST_AD_MOD_GROUP_MODS_CB,winsync_post_ad_mod_mods_cb,thefunc)
+        (*thefunc)(cookie, rawentry, local_dn, ds_entry, origmods, remote_dn, modstosend, result);
+    WINSYNC_PLUGIN_CALL_PLUGINS_END;
+
+    return;
+}
+
+
+/*
+  The following are sample code stubs to show how to implement
+  a plugin which uses this api
+*/
+
+#define WINSYNC_SAMPLE_CODE
+#ifdef WINSYNC_SAMPLE_CODE
+
+#include "slapi-plugin.h"
+#include "winsync-plugin.h"
+
+static char *test_winsync_plugin_name = "test_winsync_api";
+
+static void *
+test_winsync_api_init(const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_init [%s] [%s] -- begin\n",
+                    slapi_sdn_get_dn(ds_subtree),
+                    slapi_sdn_get_dn(ad_subtree));
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_init -- end\n");
+
+    return NULL;
+}
+
+static void
+test_winsync_dirsync_search_params_cb(void *cbdata, const char *agmt_dn,
+                                      char **base, int *scope, char **filter,
+                                      char ***attrs, LDAPControl ***serverctrls)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_dirsync_search_params_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_dirsync_search_params_cb -- end\n");
+
+    return;
+}
+
+/* called before searching for a single entry from AD - agmt_dn will be NULL */
+static void
+test_winsync_pre_ad_search_cb(void *cbdata, const char *agmt_dn,
+                              char **base, int *scope, char **filter,
+                              char ***attrs, LDAPControl ***serverctrls)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_search_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_search_cb -- end\n");
+
+    return;
+}
+
+/* called before an internal search to get a single DS entry - agmt_dn will be NULL */
+static void
+test_winsync_pre_ds_search_entry_cb(void *cbdata, const char *agmt_dn,
+                                    char **base, int *scope, char **filter,
+                                    char ***attrs, LDAPControl ***serverctrls)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ds_search_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ds_search_cb -- end\n");
+
+    return;
+}
+
+/* called before the total update to get all entries from the DS to sync to AD */
+static void
+test_winsync_pre_ds_search_all_cb(void *cbdata, const char *agmt_dn,
+                                  char **base, int *scope, char **filter,
+                                  char ***attrs, LDAPControl ***serverctrls)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ds_search_all_cb -- orig filter [%s] -- begin\n",
+                    ((filter && *filter) ? *filter : "NULL"));
+
+    /* We only want to grab users from the ds side - no groups */
+    slapi_ch_free_string(filter);
+    /* maybe use ntUniqueId=* - only get users that have already been
+       synced with AD already - ntUniqueId and ntUserDomainId are
+       indexed for equality only - need to add presence? */
+    *filter = slapi_ch_strdup("(&(objectclass=ntuser)(ntUserDomainId=*))");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ds_search_all_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ad_mod_user_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
+                                Slapi_Mods *smods, int *do_modify)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_mod_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_mod_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ad_mod_group_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
+                                Slapi_Mods *smods, int *do_modify)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_mod_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_mod_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ds_mod_user_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
+                                Slapi_Mods *smods, int *do_modify)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ds_mod_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ds_mod_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ds_mod_group_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
+                                Slapi_Mods *smods, int *do_modify)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ds_mod_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ds_mod_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ds_add_user_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ds_add_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ds_add_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ds_add_group_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ds_add_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ds_add_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_get_new_ds_user_dn_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                   Slapi_Entry *ad_entry, char **new_dn_string,
+                                   const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix)
+{
+    char **rdns = NULL;
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_get_new_ds_user_dn_cb -- old dn [%s] -- begin\n",
+                    *new_dn_string);
 
-    if (!thefunc) {
+    rdns = slapi_ldap_explode_dn(*new_dn_string, 0);
+    if (!rdns || !rdns[0]) {
+        slapi_ldap_value_free(rdns);
         return;
     }
 
-    (*thefunc)(windows_private_get_api_cookie(ra), rawentry, local_dn,
-               ds_entry, origmods, remote_dn, modstosend, result);
+    slapi_ch_free_string(new_dn_string);
+    *new_dn_string = PR_smprintf("%s,%s", rdns[0], slapi_sdn_get_dn(ds_suffix));
+    slapi_ldap_value_free(rdns);
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_get_new_ds_user_dn_cb -- new dn [%s] -- end\n",
+                    *new_dn_string);
+
+    return;
+}
+
+static void
+test_winsync_get_new_ds_group_dn_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                   Slapi_Entry *ad_entry, char **new_dn_string,
+                                   const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_get_new_ds_group_dn_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_get_new_ds_group_dn_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ad_mod_user_mods_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                     const Slapi_Entry *ds_entry,
+                                     const Slapi_DN *local_dn, LDAPMod * const *origmods,
+                                     Slapi_DN *remote_dn, LDAPMod ***modstosend)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_mod_user_mods_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_mod_user_mods_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ad_mod_group_mods_cb(void *cbdata, const Slapi_Entry *rawentry,
+                                     const Slapi_Entry *ds_entry,
+                                     const Slapi_DN *local_dn, LDAPMod * const *origmods,
+                                     Slapi_DN *remote_dn, LDAPMod ***modstosend)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_mod_group_mods_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_mod_group_mods_cb -- end\n");
+
+    return;
+}
+
+static int
+test_winsync_can_add_entry_to_ad_cb(void *cbdata, const Slapi_Entry *local_entry,
+                                    const Slapi_DN *remote_dn)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_can_add_entry_to_ad_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_can_add_entry_to_ad_cb -- end\n");
+
+    /*    return 0;*/ /* false - do not allow entries to be added to ad */
+    return 1; /* true - allow entries to be added to ad */
+}
+
+static void
+test_winsync_begin_update_cb(void *cbdata, const Slapi_DN *ds_subtree,
+                             const Slapi_DN *ad_subtree, int is_total)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_begin_update_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_begin_update_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_end_update_cb(void *cbdata, const Slapi_DN *ds_subtree,
+                           const Slapi_DN *ad_subtree, int is_total)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_end_update_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_end_update_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_destroy_agmt_cb(void *cbdata, const Slapi_DN *ds_subtree,
+                             const Slapi_DN *ad_subtree)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_destroy_agmt_cb -- begin\n");
+
+    /* free(cbdata); */
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_destroy_agmt_cb -- end\n");
 
     return;
 }
 
+static void
+test_winsync_post_ad_mod_user_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ad_mod_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of modifying AD entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ad_mod_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ad_mod_group_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ad_mod_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of modifying AD entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ad_mod_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ds_mod_user_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ds_mod_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of modifying DS entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ds_mod_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ds_mod_group_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ds_mod_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of modifying DS entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ds_mod_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ds_add_user_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ds_add_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of adding DS entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ds_add_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ds_add_group_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ds_add_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of adding DS entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ds_add_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ad_add_user_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_add_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Adding AD entry [%s] from add of DS entry [%s]\n",
+                    slapi_entry_get_dn(ad_entry), slapi_entry_get_dn(ds_entry));
+    /* make modifications to ad_entry here */
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_add_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_pre_ad_add_group_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_pre_ad_add_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Adding AD entry [%s] from add of DS entry [%s]\n",
+                    slapi_entry_get_dn(ad_entry), slapi_entry_get_dn(ds_entry));
+    /* make modifications to ad_entry here */
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_pre_ad_add_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ad_add_user_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ad_add_user_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of adding AD entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ad_add_user_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ad_add_group_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ad_add_group_cb -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of adding AD entry [%s] was [%d:%s]\n",
+                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ad_add_group_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ad_mod_user_mods_cb(void *cookie, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, const Slapi_Entry *ds_entry, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ad_mod_user_mods_cb  -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of modifying AD entry [%s] was [%d:%s]\n",
+                    slapi_sdn_get_dn(remote_dn), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ad_mod_user_mods_cb -- end\n");
+
+    return;
+}
+
+static void
+test_winsync_post_ad_mod_group_mods_cb(void *cookie, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, const Slapi_Entry *ds_entry, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend, int *result)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_post_ad_mod_group_mods_cb  -- begin\n");
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "Result of modifying AD entry [%s] was [%d:%s]\n",
+                    slapi_sdn_get_dn(remote_dn), *result, ldap_err2string(*result));
+    
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_post_ad_mod_group_mods_cb -- end\n");
+
+    return;
+}
+
+static int
+test_winsync_precedence(void)
+{
+    return 99;
+}
+
+/**
+ * Plugin identifiers
+ */
+static Slapi_PluginDesc test_winsync_pdesc = {
+    "test-winsync-plugin",
+    VENDOR,
+    DS_PACKAGE_VERSION,
+    "test winsync plugin"
+};
+
+static Slapi_ComponentId *test_winsync_plugin_id = NULL;
+
+#ifdef TEST_V1_WINSYNC_API
+static void *test_winsync_api_v1[] = {
+    NULL, /* reserved for api broker use, must be zero */
+    test_winsync_api_init,
+    test_winsync_dirsync_search_params_cb,
+    test_winsync_pre_ad_search_cb,
+    test_winsync_pre_ds_search_entry_cb,
+    test_winsync_pre_ds_search_all_cb,
+    test_winsync_pre_ad_mod_user_cb,
+    test_winsync_pre_ad_mod_group_cb,
+    test_winsync_pre_ds_mod_user_cb,
+    test_winsync_pre_ds_mod_group_cb,
+    test_winsync_pre_ds_add_user_cb,
+    test_winsync_pre_ds_add_group_cb,
+    test_winsync_get_new_ds_user_dn_cb,
+    test_winsync_get_new_ds_group_dn_cb,
+    test_winsync_pre_ad_mod_user_mods_cb,
+    test_winsync_pre_ad_mod_group_mods_cb,
+    test_winsync_can_add_entry_to_ad_cb,
+    test_winsync_begin_update_cb,
+    test_winsync_end_update_cb,
+    test_winsync_destroy_agmt_cb
+};
+#endif /* TEST_V1_WINSYNC_API */
+
+#ifdef TEST_V2_WINSYNC_API
+static void *test_winsync_api_v2[] = {
+    NULL, /* reserved for api broker use, must be zero */
+    test_winsync_api_init,
+    test_winsync_dirsync_search_params_cb,
+    test_winsync_pre_ad_search_cb,
+    test_winsync_pre_ds_search_entry_cb,
+    test_winsync_pre_ds_search_all_cb,
+    test_winsync_pre_ad_mod_user_cb,
+    test_winsync_pre_ad_mod_group_cb,
+    test_winsync_pre_ds_mod_user_cb,
+    test_winsync_pre_ds_mod_group_cb,
+    test_winsync_pre_ds_add_user_cb,
+    test_winsync_pre_ds_add_group_cb,
+    test_winsync_get_new_ds_user_dn_cb,
+    test_winsync_get_new_ds_group_dn_cb,
+    test_winsync_pre_ad_mod_user_mods_cb,
+    test_winsync_pre_ad_mod_group_mods_cb,
+    test_winsync_can_add_entry_to_ad_cb,
+    test_winsync_begin_update_cb,
+    test_winsync_end_update_cb,
+    test_winsync_destroy_agmt_cb,
+    test_winsync_post_ad_mod_user_cb,
+    test_winsync_post_ad_mod_group_cb,
+    test_winsync_post_ds_mod_user_cb,
+    test_winsync_post_ds_mod_group_cb,
+    test_winsync_post_ds_add_user_cb,
+    test_winsync_post_ds_add_group_cb,
+    test_winsync_pre_ad_add_user_cb,
+    test_winsync_pre_ad_add_group_cb,
+    test_winsync_post_ad_add_user_cb,
+    test_winsync_post_ad_add_group_cb,
+    test_winsync_post_ad_mod_user_mods_cb,
+    test_winsync_post_ad_mod_group_mods_cb
+};
+#endif /* TEST_V2_WINSYNC_API */
+
+static void *test_winsync_api_v3[] = {
+    NULL, /* reserved for api broker use, must be zero */
+    test_winsync_api_init,
+    test_winsync_dirsync_search_params_cb,
+    test_winsync_pre_ad_search_cb,
+    test_winsync_pre_ds_search_entry_cb,
+    test_winsync_pre_ds_search_all_cb,
+    test_winsync_pre_ad_mod_user_cb,
+    test_winsync_pre_ad_mod_group_cb,
+    test_winsync_pre_ds_mod_user_cb,
+    test_winsync_pre_ds_mod_group_cb,
+    test_winsync_pre_ds_add_user_cb,
+    test_winsync_pre_ds_add_group_cb,
+    test_winsync_get_new_ds_user_dn_cb,
+    test_winsync_get_new_ds_group_dn_cb,
+    test_winsync_pre_ad_mod_user_mods_cb,
+    test_winsync_pre_ad_mod_group_mods_cb,
+    test_winsync_can_add_entry_to_ad_cb,
+    test_winsync_begin_update_cb,
+    test_winsync_end_update_cb,
+    test_winsync_destroy_agmt_cb,
+    test_winsync_post_ad_mod_user_cb,
+    test_winsync_post_ad_mod_group_cb,
+    test_winsync_post_ds_mod_user_cb,
+    test_winsync_post_ds_mod_group_cb,
+    test_winsync_post_ds_add_user_cb,
+    test_winsync_post_ds_add_group_cb,
+    test_winsync_pre_ad_add_user_cb,
+    test_winsync_pre_ad_add_group_cb,
+    test_winsync_post_ad_add_user_cb,
+    test_winsync_post_ad_add_group_cb,
+    test_winsync_post_ad_mod_user_mods_cb,
+    test_winsync_post_ad_mod_group_mods_cb,
+    test_winsync_precedence
+};
+
+static int
+test_winsync_plugin_start(Slapi_PBlock *pb)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_plugin_start -- begin\n");
+
+	if( slapi_apib_register(WINSYNC_v3_0_GUID, test_winsync_api_v3) ) {
+        slapi_log_error( SLAPI_LOG_FATAL, test_winsync_plugin_name,
+                         "<-- test_winsync_plugin_start -- failed to register winsync api -- end\n");
+        return -1;
+	}
+	
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_plugin_start -- end\n");
+	return 0;
+}
+
+static int
+test_winsync_plugin_close(Slapi_PBlock *pb)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_plugin_close -- begin\n");
+
+	slapi_apib_unregister(WINSYNC_v3_0_GUID);
+
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "<-- test_winsync_plugin_close -- end\n");
+	return 0;
+}
+
+/* this is the slapi plugin init function,
+   not the one used by the winsync api
+*/
+int test_winsync_plugin_init(Slapi_PBlock *pb)
+{
+    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                    "--> test_winsync_plugin_init -- begin\n");
+
+    if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+                           SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+         slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+                          (void *) test_winsync_plugin_start ) != 0 ||
+         slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+                          (void *) test_winsync_plugin_close ) != 0 ||
+         slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+                           (void *)&test_winsync_pdesc ) != 0 )
+    {
+        slapi_log_error( SLAPI_LOG_FATAL, test_winsync_plugin_name,
+                         "<-- test_winsync_plugin_init -- failed to register plugin -- end\n");
+        return -1;
+    }
+
+    /* Retrieve and save the plugin identity to later pass to
+       internal operations */
+    if (slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &test_winsync_plugin_id) != 0) {
+        slapi_log_error(SLAPI_LOG_FATAL, test_winsync_plugin_name,
+                         "<-- test_winsync_plugin_init -- failed to retrieve plugin identity -- end\n");
+        return -1;
+    }
+
+    slapi_log_error( SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
+                     "<-- test_winsync_plugin_init -- end\n");
+    return 0;
+}
+
+/*
+dn: cn=Test Winsync API,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Test Winsync API
+nsslapd-pluginpath: libtestwinsync-plugin
+nsslapd-plugininitfunc: test_winsync_plugin_init
+nsslapd-plugintype: preoperation
+nsslapd-pluginenabled: on
+nsslapd-plugin-depends-on-type: database
+nsslapd-pluginDescription: Test Winsync
+nsslapd-pluginVendor: 389 project
+nsslapd-pluginId: test-winsync
+nsslapd-pluginVersion: 0.9
+*/
+
+#endif /* WINSYNC_SAMPLE_CODE */
+
 /* #define WINSYNC_TEST_IPA */
 #ifdef WINSYNC_TEST_IPA
 
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c
index a2ec448..518a133 100644
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
@@ -4317,11 +4317,40 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
 							slapi_valueset_free(restricted_local_values);
 							restricted_local_values = NULL;
 						}
+						else
+						{
+							slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+											"windows_generate_update_mods: no restricted local values found for "
+											"local attribute %s in local entry %s for remote attribute "
+											"%s in remote entry %s\n",
+											local_type ? local_type : "NULL",
+											local_entry ? slapi_entry_get_dn(local_entry) : "NULL",
+											type ? type : "NULL",
+											remote_entry ? slapi_entry_get_dn(remote_entry) : "NULL");
+						}
 						slapi_valueset_free(local_values);
 						local_values = NULL;
+					} else {
+						slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+										"windows_generate_update_mods: no local values found for "
+										"local attribute %s in local entry %s for remote attribute "
+										"%s in remote entry %s\n",
+										local_type ? local_type : "NULL",
+										local_entry ? slapi_entry_get_dn(local_entry) : "NULL",
+										type ? type : "NULL",
+										remote_entry ? slapi_entry_get_dn(remote_entry) : "NULL");
 					}
 					slapi_valueset_free(mapped_remote_values);
 					mapped_remote_values = NULL;
+				} else {
+					slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+									"windows_generate_update_mods: could not map the values in "
+									"local attribute %s in local entry %s for remote attribute "
+									"%s in remote entry %s\n",
+									local_type ? local_type : "NULL",
+									local_entry ? slapi_entry_get_dn(local_entry) : "NULL",
+									type ? type : "NULL",
+									remote_entry ? slapi_entry_get_dn(remote_entry) : "NULL");
 				}
 			}
 		} else
diff --git a/ldap/servers/plugins/replication/windowsrepl.h b/ldap/servers/plugins/replication/windowsrepl.h
index 7da855c..5780e74 100644
--- a/ldap/servers/plugins/replication/windowsrepl.h
+++ b/ldap/servers/plugins/replication/windowsrepl.h
@@ -146,6 +146,7 @@ int windows_check_user_password(Repl_Connection *conn, Slapi_DN *sdn, char *pass
    specific data
 */
 void windows_plugin_init(Repl_Agmt *ra);
+void windows_plugin_cleanup_agmt(Repl_Agmt *ra);
 
 void winsync_plugin_call_dirsync_search_params_cb(const Repl_Agmt *ra, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls);
 /* called before searching for a single entry from AD - agmt_dn will be NULL */
diff --git a/ldap/servers/plugins/replication/winsync-plugin.h b/ldap/servers/plugins/replication/winsync-plugin.h
index 9ac5621..0f3b757 100644
--- a/ldap/servers/plugins/replication/winsync-plugin.h
+++ b/ldap/servers/plugins/replication/winsync-plugin.h
@@ -50,6 +50,7 @@
  */
 #define WINSYNC_v1_0_GUID "CDA8F029-A3C6-4EBB-80B8-A2E183DB0481"
 #define WINSYNC_v2_0_GUID "706B83AA-FC51-444A-ACC9-53DC73D641D4"
+#define WINSYNC_v3_0_GUID "6D7C2E54-638C-4564-B53F-D9C5354DEBA0"
 
 /*
  * This callback is called when a winsync agreement is created.
@@ -274,654 +275,12 @@ typedef void (*winsync_post_ad_mod_mods_cb)(void *cookie, const Slapi_Entry *raw
 #define WINSYNC_PLUGIN_POST_AD_MOD_USER_MODS_CB 30
 #define WINSYNC_PLUGIN_POST_AD_MOD_GROUP_MODS_CB 31
 #define WINSYNC_PLUGIN_VERSION_2_END WINSYNC_PLUGIN_POST_AD_MOD_GROUP_MODS_CB
-/*
-  The following are sample code stubs to show how to implement
-  a plugin which uses this api
-*/
-
-/* #define WINSYNC_SAMPLE_CODE */
-#ifdef WINSYNC_SAMPLE_CODE
-
-#include "slapi-plugin.h"
-#include "winsync-plugin.h"
-
-static char *test_winsync_plugin_name = "test_winsync_api";
-
-static void *
-test_winsync_api_init(const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_init [%s] [%s] -- begin\n",
-                    slapi_sdn_get_dn(ds_subtree),
-                    slapi_sdn_get_dn(ad_subtree));
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_init -- end\n");
-
-    return NULL;
-}
-
-static void
-test_winsync_dirsync_search_params_cb(void *cbdata, const char *agmt_dn,
-                                      char **base, int *scope, char **filter,
-                                      char ***attrs, LDAPControl ***serverctrls)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_dirsync_search_params_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_dirsync_search_params_cb -- end\n");
-
-    return;
-}
-
-/* called before searching for a single entry from AD - agmt_dn will be NULL */
-static void
-test_winsync_pre_ad_search_cb(void *cbdata, const char *agmt_dn,
-                              char **base, int *scope, char **filter,
-                              char ***attrs, LDAPControl ***serverctrls)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_search_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_search_cb -- end\n");
-
-    return;
-}
-
-/* called before an internal search to get a single DS entry - agmt_dn will be NULL */
-static void
-test_winsync_pre_ds_search_entry_cb(void *cbdata, const char *agmt_dn,
-                                    char **base, int *scope, char **filter,
-                                    char ***attrs, LDAPControl ***serverctrls)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ds_search_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ds_search_cb -- end\n");
-
-    return;
-}
-
-/* called before the total update to get all entries from the DS to sync to AD */
-static void
-test_winsync_pre_ds_search_all_cb(void *cbdata, const char *agmt_dn,
-                                  char **base, int *scope, char **filter,
-                                  char ***attrs, LDAPControl ***serverctrls)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ds_search_all_cb -- orig filter [%s] -- begin\n",
-                    ((filter && *filter) ? *filter : "NULL"));
-
-    /* We only want to grab users from the ds side - no groups */
-    slapi_ch_free_string(filter);
-    /* maybe use ntUniqueId=* - only get users that have already been
-       synced with AD already - ntUniqueId and ntUserDomainId are
-       indexed for equality only - need to add presence? */
-    *filter = slapi_ch_strdup("(&(objectclass=ntuser)(ntUserDomainId=*))");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ds_search_all_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ad_mod_user_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
-                                Slapi_Mods *smods, int *do_modify)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_mod_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_mod_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ad_mod_group_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
-                                Slapi_Mods *smods, int *do_modify)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_mod_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_mod_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ds_mod_user_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
-                                Slapi_Mods *smods, int *do_modify)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ds_mod_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ds_mod_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ds_mod_group_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry,
-                                Slapi_Mods *smods, int *do_modify)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ds_mod_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ds_mod_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ds_add_user_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ds_add_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ds_add_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ds_add_group_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                Slapi_Entry *ad_entry, Slapi_Entry *ds_entry)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ds_add_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ds_add_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_get_new_ds_user_dn_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                   Slapi_Entry *ad_entry, char **new_dn_string,
-                                   const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix)
-{
-    char **rdns = NULL;
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_get_new_ds_user_dn_cb -- old dn [%s] -- begin\n",
-                    *new_dn_string);
-
-    rdns = slapi_ldap_explode_dn(*new_dn_string, 0);
-    if (!rdns || !rdns[0]) {
-        slapi_ldap_value_free(rdns);
-        return;
-    }
-
-    slapi_ch_free_string(new_dn_string);
-    *new_dn_string = PR_smprintf("%s,%s", rdns[0], slapi_sdn_get_dn(ds_suffix));
-    slapi_ldap_value_free(rdns);
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_get_new_ds_user_dn_cb -- new dn [%s] -- end\n",
-                    *new_dn_string);
-
-    return;
-}
-
-static void
-test_winsync_get_new_ds_group_dn_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                   Slapi_Entry *ad_entry, char **new_dn_string,
-                                   const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_get_new_ds_group_dn_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_get_new_ds_group_dn_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ad_mod_user_mods_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                     const Slapi_Entry *ds_entry,
-                                     const Slapi_DN *local_dn, LDAPMod * const *origmods,
-                                     Slapi_DN *remote_dn, LDAPMod ***modstosend)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_mod_user_mods_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_mod_user_mods_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ad_mod_group_mods_cb(void *cbdata, const Slapi_Entry *rawentry,
-                                     const Slapi_Entry *ds_entry,
-                                     const Slapi_DN *local_dn, LDAPMod * const *origmods,
-                                     Slapi_DN *remote_dn, LDAPMod ***modstosend)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_mod_group_mods_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_mod_group_mods_cb -- end\n");
-
-    return;
-}
-
-static int
-test_winsync_can_add_entry_to_ad_cb(void *cbdata, const Slapi_Entry *local_entry,
-                                    const Slapi_DN *remote_dn)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_can_add_entry_to_ad_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_can_add_entry_to_ad_cb -- end\n");
-
-    /*    return 0;*/ /* false - do not allow entries to be added to ad */
-    return 1; /* true - allow entries to be added to ad */
-}
-
-static void
-test_winsync_begin_update_cb(void *cbdata, const Slapi_DN *ds_subtree,
-                             const Slapi_DN *ad_subtree, int is_total)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_begin_update_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_begin_update_cb -- end\n");
 
-    return;
-}
-
-static void
-test_winsync_end_update_cb(void *cbdata, const Slapi_DN *ds_subtree,
-                           const Slapi_DN *ad_subtree, int is_total)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_end_update_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_end_update_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_destroy_agmt_cb(void *cbdata, const Slapi_DN *ds_subtree,
-                             const Slapi_DN *ad_subtree)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_destroy_agmt_cb -- begin\n");
-
-    /* free(cbdata); */
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_destroy_agmt_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ad_mod_user_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ad_mod_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of modifying AD entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ad_mod_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ad_mod_group_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ad_mod_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of modifying AD entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ad_mod_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ds_mod_user_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ds_mod_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of modifying DS entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ds_mod_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ds_mod_group_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ds_mod_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of modifying DS entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ds_mod_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ds_add_user_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ds_add_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of adding DS entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ds_add_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ds_add_group_cb(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ds_add_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of adding DS entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ds_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ds_add_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ad_add_user_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_add_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Adding AD entry [%s] from add of DS entry [%s]\n",
-                    slapi_entry_get_dn(ad_entry), slapi_entry_get_dn(ds_entry));
-    /* make modifications to ad_entry here */
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_add_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_pre_ad_add_group_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_pre_ad_add_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Adding AD entry [%s] from add of DS entry [%s]\n",
-                    slapi_entry_get_dn(ad_entry), slapi_entry_get_dn(ds_entry));
-    /* make modifications to ad_entry here */
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_pre_ad_add_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ad_add_user_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ad_add_user_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of adding AD entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ad_add_user_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ad_add_group_cb(void *cookie, Slapi_Entry *ds_entry, Slapi_Entry *ad_entry, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ad_add_group_cb -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of adding AD entry [%s] was [%d:%s]\n",
-                    slapi_entry_get_dn(ad_entry), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ad_add_group_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ad_mod_user_mods_cb(void *cookie, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, const Slapi_Entry *ds_entry, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ad_mod_user_mods_cb  -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of modifying AD entry [%s] was [%d:%s]\n",
-                    slapi_sdn_get_dn(remote_dn), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ad_mod_user_mods_cb -- end\n");
-
-    return;
-}
-
-static void
-test_winsync_post_ad_mod_group_mods_cb(void *cookie, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, const Slapi_Entry *ds_entry, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend, int *result)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_post_ad_mod_group_mods_cb  -- begin\n");
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "Result of modifying AD entry [%s] was [%d:%s]\n",
-                    slapi_sdn_get_dn(remote_dn), *result, ldap_err2string(*result));
-    
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_post_ad_mod_group_mods_cb -- end\n");
-
-    return;
-}
-
-/**
- * Plugin identifiers
- */
-static Slapi_PluginDesc test_winsync_pdesc = {
-    "test-winsync-plugin",
-    VENDOR,
-    DS_PACKAGE_VERSION,
-    "test winsync plugin"
-};
-
-static Slapi_ComponentId *test_winsync_plugin_id = NULL;
-
-#ifdef TEST_V1_WINSYNC_API
-static void *test_winsync_api_v1[] = {
-    NULL, /* reserved for api broker use, must be zero */
-    test_winsync_api_init,
-    test_winsync_dirsync_search_params_cb,
-    test_winsync_pre_ad_search_cb,
-    test_winsync_pre_ds_search_entry_cb,
-    test_winsync_pre_ds_search_all_cb,
-    test_winsync_pre_ad_mod_user_cb,
-    test_winsync_pre_ad_mod_group_cb,
-    test_winsync_pre_ds_mod_user_cb,
-    test_winsync_pre_ds_mod_group_cb,
-    test_winsync_pre_ds_add_user_cb,
-    test_winsync_pre_ds_add_group_cb,
-    test_winsync_get_new_ds_user_dn_cb,
-    test_winsync_get_new_ds_group_dn_cb,
-    test_winsync_pre_ad_mod_user_mods_cb,
-    test_winsync_pre_ad_mod_group_mods_cb,
-    test_winsync_can_add_entry_to_ad_cb,
-    test_winsync_begin_update_cb,
-    test_winsync_end_update_cb,
-    test_winsync_destroy_agmt_cb
-};
-#endif /* TEST_V1_WINSYNC_API */
-
-static void *test_winsync_api_v2[] = {
-    NULL, /* reserved for api broker use, must be zero */
-    test_winsync_api_init,
-    test_winsync_dirsync_search_params_cb,
-    test_winsync_pre_ad_search_cb,
-    test_winsync_pre_ds_search_entry_cb,
-    test_winsync_pre_ds_search_all_cb,
-    test_winsync_pre_ad_mod_user_cb,
-    test_winsync_pre_ad_mod_group_cb,
-    test_winsync_pre_ds_mod_user_cb,
-    test_winsync_pre_ds_mod_group_cb,
-    test_winsync_pre_ds_add_user_cb,
-    test_winsync_pre_ds_add_group_cb,
-    test_winsync_get_new_ds_user_dn_cb,
-    test_winsync_get_new_ds_group_dn_cb,
-    test_winsync_pre_ad_mod_user_mods_cb,
-    test_winsync_pre_ad_mod_group_mods_cb,
-    test_winsync_can_add_entry_to_ad_cb,
-    test_winsync_begin_update_cb,
-    test_winsync_end_update_cb,
-    test_winsync_destroy_agmt_cb,
-    test_winsync_post_ad_mod_user_cb,
-    test_winsync_post_ad_mod_group_cb,
-    test_winsync_post_ds_mod_user_cb,
-    test_winsync_post_ds_mod_group_cb,
-    test_winsync_post_ds_add_user_cb,
-    test_winsync_post_ds_add_group_cb,
-    test_winsync_pre_ad_add_user_cb,
-    test_winsync_pre_ad_add_group_cb,
-    test_winsync_post_ad_add_user_cb,
-    test_winsync_post_ad_add_group_cb,
-    test_winsync_post_ad_mod_user_mods_cb,
-    test_winsync_post_ad_mod_group_mods_cb
-};
-
-static int
-test_winsync_plugin_start(Slapi_PBlock *pb)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_plugin_start -- begin\n");
-
-	if( slapi_apib_register(WINSYNC_v2_0_GUID, test_winsync_api_v2) ) {
-        slapi_log_error( SLAPI_LOG_FATAL, test_winsync_plugin_name,
-                         "<-- test_winsync_plugin_start -- failed to register winsync api -- end\n");
-        return -1;
-	}
-	
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_plugin_start -- end\n");
-	return 0;
-}
-
-static int
-test_winsync_plugin_close(Slapi_PBlock *pb)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_plugin_close -- begin\n");
-
-	slapi_apib_unregister(WINSYNC_v2_0_GUID);
-
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "<-- test_winsync_plugin_close -- end\n");
-	return 0;
-}
-
-/* this is the slapi plugin init function,
-   not the one used by the winsync api
-*/
-int test_winsync_plugin_init(Slapi_PBlock *pb)
-{
-    slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                    "--> test_winsync_plugin_init -- begin\n");
-
-    if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
-                           SLAPI_PLUGIN_VERSION_01 ) != 0 ||
-         slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
-                          (void *) test_winsync_plugin_start ) != 0 ||
-         slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
-                          (void *) test_winsync_plugin_close ) != 0 ||
-         slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
-                           (void *)&test_winsync_pdesc ) != 0 )
-    {
-        slapi_log_error( SLAPI_LOG_FATAL, test_winsync_plugin_name,
-                         "<-- test_winsync_plugin_init -- failed to register plugin -- end\n");
-        return -1;
-    }
-
-    /* Retrieve and save the plugin identity to later pass to
-       internal operations */
-    if (slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &test_winsync_plugin_id) != 0) {
-        slapi_log_error(SLAPI_LOG_FATAL, test_winsync_plugin_name,
-                         "<-- test_winsync_plugin_init -- failed to retrieve plugin identity -- end\n");
-        return -1;
-    }
-
-    slapi_log_error( SLAPI_LOG_PLUGIN, test_winsync_plugin_name,
-                     "<-- test_winsync_plugin_init -- end\n");
-    return 0;
-}
-
-/*
-dn: cn=Test Winsync API,cn=plugins,cn=config
-objectclass: top
-objectclass: nsSlapdPlugin
-objectclass: extensibleObject
-cn: Test Winsync API
-nsslapd-pluginpath: libtestwinsync-plugin
-nsslapd-plugininitfunc: test_winsync_plugin_init
-nsslapd-plugintype: preoperation
-nsslapd-pluginenabled: on
-nsslapd-plugin-depends-on-type: database
-nsslapd-plugin-depends-on-named: Multimaster Replication Plugin
-*/
+typedef int (*winsync_plugin_precedence_cb)(void);
+#define WINSYNC_PLUGIN_PRECEDENCE_CB 32
+#define WINSYNC_PLUGIN_VERSION_3_END WINSYNC_PLUGIN_PRECEDENCE_CB
 
-#endif /* WINSYNC_SAMPLE_CODE */
+/* precedence works like regular slapi plugin precedence */
+#define WINSYNC_PLUGIN_DEFAULT_PRECEDENCE 50
 
 #endif /* WINSYNC_PLUGIN_PUBLIC_API */
diff --git a/ldap/servers/slapd/apibroker.c b/ldap/servers/slapd/apibroker.c
index 2987716..9937b88 100644
--- a/ldap/servers/slapd/apibroker.c
+++ b/ldap/servers/slapd/apibroker.c
@@ -72,6 +72,7 @@ typedef struct _API_FEATURES
 static ABAPI *head = NULL;
 
 static ABAPI **ABAPIBroker_FindInterface(char *guid);
+static void ***ABAPIBroker_FindInterface_All(char *guid);
 
 int slapi_apib_register(char *guid, void **api )
 {
@@ -188,6 +189,39 @@ int slapi_apib_get_interface(char *guid, void ***api)
 	return ret;
 }
 
+int slapi_apib_get_interface_all(char *guid, void ****api)
+{
+	void ***retapi = NULL;
+	int idx = 0;
+
+	if(buffer_lock == 0)
+		return -1;
+
+	if(buffer_lock == 0)
+	{
+		if(0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
+			/* badness */
+			return -1;
+	}
+
+	slapi_lock_mutex(buffer_lock);
+
+	retapi = ABAPIBroker_FindInterface_All(guid);
+	for (idx = 0; retapi && retapi[idx]; ++idx) {
+		void **theapi = retapi[idx];
+		if(theapi[0])
+		{
+			slapi_apib_addref(theapi);
+		}
+	}
+
+	*api = retapi;
+
+	slapi_unlock_mutex(buffer_lock);
+
+	return 0;
+}
+
 int slapi_apib_make_reference_counted(void **api, slapi_apib_callback_on_zero callback_on_zero)
 {
 	int ret = -1;
@@ -280,3 +314,27 @@ static ABAPI **ABAPIBroker_FindInterface(char *guid)
 
 	return 0;
 }
+
+static void ***ABAPIBroker_FindInterface_All(char *guid)
+{
+	ABAPI *api = NULL;
+	ABAPI *start_api = head;
+	void ***apilist = NULL;
+	int idx = 0;
+
+	api = start_api;
+	if (!api) {
+		return NULL;
+	}
+
+	do {
+		if(0 == strcmp(guid, api->guid)) {
+			apilist = (void ***)slapi_ch_realloc((char *)apilist, (idx+2)*sizeof(void **));
+			apilist[idx++] = api->api;
+			apilist[idx] = NULL;
+		}
+		api = api->next;
+	} while(api != start_api);
+
+	return apilist;
+}
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index f238bef..a9d7dfe 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5082,6 +5082,20 @@ int slapi_apib_unregister(char *guid); /* remove interface from published list *
 */
 int slapi_apib_get_interface(char *guid, void ***api); /* retrieve an interface for use */
 
+/* Function:	slapi_apib_get_interface_all
+   Description:	this function allows retrieval of a published interface,
+		    if the api reference counted, then the reference
+		    count is incremented
+            This will return all published interfaces for a given guid
+   Parameters:	guid - a string constant that uniquely identifies the
+		    interface requested
+		apilist - the retrieved list of vtables for the published api - caller
+            must free the apilist, but not the apilist elements
+   Return:	0 if function succeeds
+		non-zero otherwise
+*/
+int slapi_apib_get_interface_all(char *guid, void ****apilist); /* retrieve all interfaces for guid */
+
 
 /* Function:	slapi_apib_make_reference_counted
    Description:	this function makes an interface a reference counted interface


commit d68b40c3b5638f5160ff12584bb535dac6cb6628
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Fri Aug 3 11:28:43 2012 -0400

    Ticket 403 - cleanallruv coverity fixes
    
    Fixed coverity issues
    
    Reviewed by: richm(Thanks Rich!)
    (cherry picked from commit 75e5d3d1dba984f0219512d908d1a624096c7acc)

diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 5a16083..5817f99 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -434,7 +434,8 @@ agmt_new_from_entry(Slapi_Entry *e)
 		for (i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
 			ra->cleanruv_notified[i] = atoi(clean_vals[i]);
 		}
-		ra->cleanruv_notified[i + 1] = 0;
+		if(i <= CLEANRIDSIZ)
+		    ra->cleanruv_notified[i + 1] = 0;
 		slapi_ch_array_free(clean_vals);
 	} else {
 		ra->cleanruv_notified[0] = 0;
@@ -2587,7 +2588,7 @@ agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e)
     tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaStripAttrs);
     if (NULL != tmpstr){
         if(ra->attrs_to_strip){
-            slapi_ch_array_free(&ra->attrs_to_strip);
+            slapi_ch_array_free(ra->attrs_to_strip);
         }
         ra->attrs_to_strip = slapi_str2charray_ext(tmpstr, " ", 0);
         PR_Unlock(ra->lock);
@@ -2675,7 +2676,9 @@ agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e){
         for (i = 0; i < CLEANRIDSIZ && attr_vals[i]; i++){
             ra->cleanruv_notified[i] = atoi(attr_vals[i]);
         }
-        ra->cleanruv_notified[i + 1] = 0;
+        if( i <= CLEANRIDSIZ )
+            ra->cleanruv_notified[i + 1] = 0;
+        slapi_ch_array_free(attr_vals);
     } else {
         ra->cleanruv_notified[0] = 0;
     }
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index 27cdacd..75f82ab 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -1825,7 +1825,7 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
         ReplicaId rid;
         int i;
 
-        for(i = 0; clean_vals[i]; i++){
+        for(i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
             cleanruv_data *data = NULL;
 
             /*
@@ -1863,7 +1863,8 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
             if(payload == NULL){
                 slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: Startup: Failed to "
                     "create extended op payload, aborting task");
-                return;
+                csn_free(&maxcsn);
+                goto done;
             }
             /*
              *  Setup the data struct, and fire off the thread.
@@ -1886,12 +1887,20 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
                         (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
                         PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
                 if (thread == NULL) {
+                    /* log an error and free everything */
                     slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV: unable to create cleanAllRUV "
                         "thread for rid(%d)\n", (int)data->rid);
+                    csn_free(&maxcsn);
+                    slapi_sdn_free(&data->sdn);
+                    ber_bvfree(data->payload);
+                    slapi_ch_free((void **)&data);
                 }
             }
         }
         r->repl_cleanruv_data[i] = NULL;
+
+done:
+        slapi_ch_array_free(clean_vals);
     }
 
     if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaAbortCleanRUV)) != NULL)
@@ -1915,12 +1924,12 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
                 if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
                     slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: invalid replica id(%d) "
                         "aborting task.\n", rid);
-                    goto done;
+                    goto done2;
                 }
             } else {
                 slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to parse cleanallruv "
                     "data (%s), aborting task.\n",clean_vals[i]);
-                goto done;
+                goto done2;
             }
 
             repl_root = ldap_utf8strtok_r(iter, ":", &iter);
@@ -1961,14 +1970,18 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
                     if (thread == NULL) {
                         slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to create abort cleanAllRUV "
                             "thread for rid(%d)\n", (int)data->rid);
+                        slapi_sdn_free(&data->sdn);
+                        ber_bvfree(data->payload);
+                        slapi_ch_free_string(&data->repl_root);
+                        slapi_ch_free((void **)&data);
                     }
                 }
             }
         }
-    }
 
-done:
-    slapi_ch_array_free(clean_vals);
+done2:
+        slapi_ch_array_free(clean_vals);
+    }
 }
 
 /* This function updates the entry to contain information generated 
@@ -3783,8 +3796,10 @@ replica_add_cleanruv_data(Replica *r, char *val)
     PR_Lock(r->repl_lock);
 
     for (i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] != NULL; i++); /* goto the end of the list */
-    r->repl_cleanruv_data[i] = slapi_ch_strdup(val); /* append to list */
-    r->repl_cleanruv_data[i + 1] = NULL;
+    if( i < CLEANRIDSIZ)
+        r->repl_cleanruv_data[i] = slapi_ch_strdup(val); /* append to list */
+    if(i <= CLEANRIDSIZ)
+        r->repl_cleanruv_data[i + 1] = NULL;
 
     PR_Unlock(r->repl_lock);
 }
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 89651cf..a03740b 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -1319,21 +1319,13 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, c
         /* we are already running the maximum number of tasks */
         cleanruv_log(pre_task, CLEANALLRUV_ID,
     	    "Exceeded maximum number of active CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
-        returntext = PR_smprintf("Exceeded maximum number of active CLEANALLRUV tasks(%d), "
-            "you must wait for one to finish.", CLEANRIDSIZ);
         return LDAP_UNWILLING_TO_PERFORM;
     }
 
     /*
      *  Grab the replica
      */
-    if(r){
-        replica = (Replica*)object_get_data (r);
-    } else {
-    	cleanruv_log(pre_task, CLEANALLRUV_ID, "Replica is NULL, aborting task");
-        rc = -1;
-        goto fail;
-    }
+    replica = (Replica*)object_get_data (r);
     /*
      *  Check if this is a consumer
      */
@@ -1419,7 +1411,8 @@ fail:
         ber_bvfree(payload);
     }
     csn_free(&maxcsn);
-    object_release (r);
+    if(task) /* only the task acquires the r obj */
+         object_release (r);
 
 done:
 
@@ -1476,7 +1469,7 @@ replica_cleanallruv_thread(void *arg)
     if(data->replica == NULL && data->repl_obj){
         data->replica = (Replica*)object_get_data(data->repl_obj);
     }
-    if( data->replica && data->repl_obj == NULL){
+    if( data->repl_obj == NULL){
         data->repl_obj = object_new(data->replica, NULL);
         free_obj = 1;
     }
@@ -1819,7 +1812,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
     Repl_Connection *conn;
     ConnResult crc = 0;
     LDAP *ld;
-    Slapi_DN *dn;
+    Slapi_DN *sdn;
     struct berval *vals[2];
     struct berval val;
     LDAPMod *mods[2];
@@ -1842,7 +1835,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
         return;
     }
     val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", rid);
-    dn = agmt_get_replarea(agmt);
+    sdn = agmt_get_replarea(agmt);
     mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
     mod.mod_type = "nsds5task";
     mod.mod_bvalues = vals;
@@ -1851,7 +1844,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
     val.bv_val = data;
     mods[0] = &mod;
     mods[1] = NULL;
-    repl_dn = PR_smprintf("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", slapi_sdn_get_dn(dn));
+    repl_dn = slapi_create_dn_string("cn=replica,cn=%s,cn=mapping tree,cn=config", slapi_sdn_get_dn(sdn));
     /*
      *  Add task to remote replica
      */
@@ -1863,6 +1856,7 @@ replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
             agmt_get_long_name(agmt), agmt_get_hostname(agmt), rc);
     }
     slapi_ch_free_string(&repl_dn);
+    slapi_sdn_free(&sdn);
     conn_delete_internal_ext(conn);
 }
 
@@ -1940,6 +1934,9 @@ add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
     char *dn;
     int rc;
 
+    if(r == NULL || maxcsn == NULL){
+        return;
+    }
     /*
      *  Write the rid & maxcsn to the config entry
      */
@@ -2068,13 +2065,12 @@ delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
 
     slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
     slapi_modify_internal_pb (pb);
-    slapi_pblock_destroy (pb);
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
     if (rc != LDAP_SUCCESS){
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
             "config (%d), rid (%d)\n", rc, rid);
     }
-
+    slapi_pblock_destroy (pb);
     slapi_ch_free_string(&dn);
     slapi_ch_free_string(&data);
 }
@@ -2166,7 +2162,7 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
     Replica *replica;
     ReplicaId rid;
     cleanruv_data *data = NULL;
-    const Slapi_DN *dn;
+    Slapi_DN *sdn;
     Object *r;
     CSN *maxcsn;
     const char *base_dn;
@@ -2178,8 +2174,6 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
         /* we are already running the maximum number of tasks */
         cleanruv_log(task, ABORT_CLEANALLRUV_ID,
     	    "Exceeded maximum number of active ABORT CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
-        returntext = PR_smprintf("Exceeded maximum number of active ABORT CLEANALLRUV tasks(%d), "
-            "you must wait for one to finish.", CLEANRIDSIZ);
         *returncode = LDAP_OPERATIONS_ERROR;
         return SLAPI_DSE_CALLBACK_ERROR;
     }
@@ -2216,8 +2210,8 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter
     /*
      *  Get the replica object
      */
-    dn = slapi_sdn_new_dn_byval(base_dn);
-    if((r = replica_get_replica_from_dn(dn)) == NULL){
+    sdn = slapi_sdn_new_dn_byval(base_dn);
+    if((r = replica_get_replica_from_dn(sdn)) == NULL){
         cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Failed to find replica from dn(%s)", base_dn);
         *returncode = LDAP_OPERATIONS_ERROR;
         rc = SLAPI_DSE_CALLBACK_ERROR;
@@ -2275,6 +2269,7 @@ out:
 
     csn_free(&maxcsn);
     slapi_ch_free_string(&ridstr);
+    slapi_sdn_free(&sdn);
 
     if(rc != SLAPI_DSE_CALLBACK_OK){
         cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Abort Task failed (%d)", rc);
@@ -2477,7 +2472,7 @@ replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn,
 {
     Repl_Connection *conn = NULL;
     LDAP *ld;
-    Slapi_DN *dn = agmt_get_replarea(agmt);
+    Slapi_DN *sdn;
     struct berval **vals;
     LDAPMessage *result = NULL, *entry = NULL;
     BerElement *ber;
@@ -2501,10 +2496,11 @@ replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn,
             conn_delete_internal_ext(conn);
             return -1;
         }
-        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(dn), LDAP_SCOPE_SUBTREE,
+        sdn = agmt_get_replarea(agmt);
+        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
             "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
             attrs, 0, NULL, NULL, NULL, 0, &result);
-        slapi_sdn_free(&dn);
+        slapi_sdn_free(&sdn);
         if(rc != LDAP_SUCCESS){
         	cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
                 "agmt (%s) error (%d), will retry later.", agmt_get_long_name(agmt), rc);
@@ -2530,7 +2526,7 @@ replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn,
                             for(part_count = 1; ruv_part && part_count < 5; part_count++){
                                 ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
                             }
-                            if(part_count == 5){
+                            if(part_count == 5 && ruv_part){
                                 /* we have the maxcsn */
                                 if(strcmp(ruv_part, maxcsn)){
                                     /* we are not caught up yet, free, and return */
@@ -2618,7 +2614,7 @@ replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task)
     struct berval **vals = NULL;
     LDAPMessage *result = NULL, *entry = NULL;
     LDAP *ld = NULL;
-    Slapi_DN *dn = agmt_get_replarea(ra);
+    Slapi_DN *sdn;
     char *attrs[2];
     char *attr = NULL;
     int rc = 0, i;
@@ -2637,10 +2633,11 @@ replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task)
             goto done;
         }
 
-        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(dn), LDAP_SCOPE_SUBTREE,
+        sdn = agmt_get_replarea(ra);
+        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
             "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
             attrs, 0, NULL, NULL, NULL, 0, &result);
-        slapi_sdn_free(&dn);
+        slapi_sdn_free(&sdn);
         if(rc != LDAP_SUCCESS){
             cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
                 "agmt (%s) error (%d), will retry later.", agmt_get_long_name(ra), rc);
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
index 88bb9e3..db94ba7 100644
--- a/ldap/servers/plugins/replication/repl_extop.c
+++ b/ldap/servers/plugins/replication/repl_extop.c
@@ -1499,7 +1499,7 @@ multimaster_extop_cleanruv(Slapi_PBlock *pb)
 	PRThread *thread = NULL;
 	Replica *r = NULL;
 	cleanruv_data *data = NULL;
-	CSN *maxcsn;
+	CSN *maxcsn = NULL;
 	struct berval *extop_payload;
 	struct berval *resp_bval = NULL;
 	BerElement *resp_bere = NULL;
@@ -1656,6 +1656,8 @@ free_and_return:
 		if (mtnode_ext->replica)
 			object_release (mtnode_ext->replica);
 	}
+	if(rc)
+	    csn_free(&maxcsn);
 	slapi_ch_free_string(&payload);
 
 	/*


commit ec473e3b35b4326e08eea466f5cd4a4e1e584984
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed Aug 1 18:08:29 2012 -0400

    Ticket 407 - memory leak in dna plugin
    
    Bug Description:  Valgrind reported a memory leak in dna_pre_op()
    
    Fix Description:  Moved the slapi mod allocation, and freed the mods on error.
    
    https://fedorahosted.org/389/ticket/407
    
    Reviewed by: ?
    (cherry picked from commit 9229db23f5491bf8320967387e88903334dfed94)

diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c
index ce2486e..70d9c6b 100644
--- a/ldap/servers/plugins/dna/dna.c
+++ b/ldap/servers/plugins/dna/dna.c
@@ -3247,12 +3247,8 @@ dna_pre_op(Slapi_PBlock * pb, int modtype)
                             "dna_pre_op: no pre op entry set for modify\n");
             goto bail;
         }
-        /* grab the mods - we'll put them back later with
-         * our modifications appended
-         */
+        /* grab the mods - we'll put them back later with our modifications appended */
         slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
-        smods = slapi_mods_new();
-        slapi_mods_init_passin(smods, mods);
 
         /* We need the resulting entry after the mods are applied to
          * see if the entry is within the scope. */
@@ -3263,6 +3259,8 @@ dna_pre_op(Slapi_PBlock * pb, int modtype)
              * to let the main server handle it. */
             goto bail;
         }
+        smods = slapi_mods_new();
+        slapi_mods_init_passin(&smods, mods);
     }
 
     /* For a MOD, we need to check the resulting entry */
@@ -3292,7 +3290,9 @@ dna_pre_op(Slapi_PBlock * pb, int modtype)
         if (LDAP_CHANGETYPE_ADD == modtype) {
             ret = _dna_pre_op_add(pb, test_e);
         } else {
-            ret = _dna_pre_op_modify(pb, test_e, smods);
+            if((ret = _dna_pre_op_modify(pb, test_e, smods))){
+            	slapi_mods_free(&smods);
+            }
         }
         if (ret) {
             goto bail;


commit 74b25ce9c7bf2fc05e401896238f6039c3aefb03
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed Aug 1 16:12:01 2012 -0400

    Ticket 403 - CLEANALLRUV feature
    
    This is a rewrite of the first version of CLEANALLRUV.  The task is now an official slapi task, but the
    older/original method still works as well.  You can run multiple tasks(4) at the same time.  The task can handle
    situations where a replica is down, or "older"replicas are in the topology.  I've also added an "abort"
    task to cancel a particular cleanallruv task, as the task can potentially run for a long time while
    waiting for a server to come online or be cleaned.
    
    https://fedorahosted.org/389/ticket/403
    
    Reviewed by: richm & noriko (Thanks!)
    (cherry picked from commit 657efc69487cc1b04d82642dddd47f93b7a37cf1)

diff --git a/Makefile.am b/Makefile.am
index d90cd4b..000fef0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -374,6 +374,7 @@ task_SCRIPTS = ldap/admin/src/scripts/template-bak2db \
 	ldap/admin/src/scripts/template-db2ldif.pl \
 	ldap/admin/src/scripts/template-fixup-linkedattrs.pl \
 	ldap/admin/src/scripts/template-fixup-memberof.pl \
+	ldap/admin/src/scripts/template-cleanallruv.pl \
 	ldap/admin/src/scripts/template-ldif2db.pl \
 	ldap/admin/src/scripts/template-ns-accountstatus.pl \
 	ldap/admin/src/scripts/template-ns-activate.pl \
diff --git a/Makefile.in b/Makefile.in
index 915e978..3b16974 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1590,6 +1590,7 @@ task_SCRIPTS = ldap/admin/src/scripts/template-bak2db \
 	ldap/admin/src/scripts/template-db2ldif.pl \
 	ldap/admin/src/scripts/template-fixup-linkedattrs.pl \
 	ldap/admin/src/scripts/template-fixup-memberof.pl \
+	ldap/admin/src/scripts/template-cleanallruv.pl \
 	ldap/admin/src/scripts/template-ldif2db.pl \
 	ldap/admin/src/scripts/template-ns-accountstatus.pl \
 	ldap/admin/src/scripts/template-ns-activate.pl \
diff --git a/ldap/admin/src/scripts/template-cleanallruv.pl.in b/ldap/admin/src/scripts/template-cleanallruv.pl.in
new file mode 100644
index 0000000..be95a6d
--- /dev/null
+++ b/ldap/admin/src/scripts/template-cleanallruv.pl.in
@@ -0,0 +1,186 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+# 
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+# 
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception. 
+# 
+# 
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2012 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+    print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n");
+    print(STDERR "        [-b basedn | -r rid | -A]\n");
+    print(STDERR " Opts: -D rootdn           - Directory Manager\n");
+    print(STDERR "     : -w password         - Directory Manager's password\n");
+    print(STDERR "     : -w -                - Prompt for Directory Manager's password\n");
+    print(STDERR "     : -j filename         - Read Directory Manager's password from file\n");
+    print(STDERR "     : -b basedn           - DN of the replica root you want to clean\n");
+    print(STDERR "     : -r rid              - The replica id that you want to clean\n");
+    print(STDERR "     : -A                  - Abort an existing cleanallruv task(must use with -b and -r args\n");
+    print(STDERR "     : -v                  - verbose\n");
+}
+
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$basedn = "";
+$rid = "";
+$abort = "";
+$verbose = 0;
+
+$prefix = "{{DS-ROOT}}";
+
+$ENV{'PATH'} = "$prefix at ldaptool_bindir@:$prefix/usr/bin:@ldaptool_bindir@:/usr/bin";
+
+libpath_add("$prefix at nss_libdir@");
+libpath_add("$prefix/usr/lib");
+libpath_add("@nss_libdir@");
+libpath_add("/usr/lib");
+
+$ENV{'SHLIB_PATH'} = "$ENV{'LD_LIBRARY_PATH'}";
+
+$i = 0;
+while ($i <= $#ARGV) 
+{
+    if ("$ARGV[$i]" eq "-b")
+    {
+        # Base DN
+        $i++; $basedn = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-r")
+    {
+        # rid
+        $i++; $rid = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-A")
+    {
+        # abort
+        $abort = "yes";
+    }
+    elsif ("$ARGV[$i]" eq "-D") 
+    {    
+        # Directory Manager
+        $i++; $rootdn = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-w") 
+    {    
+        # Directory Manager's password
+        $i++; $passwd = $ARGV[$i];
+    } 
+    elsif ("$ARGV[$i]" eq "-j")
+    {
+         # Read Directory Manager's password from a file
+        $i++; $passwdfile = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-v") 
+    {    
+        # verbose
+        $verbose = 1;
+    }
+    else
+    {
+        &usage; exit(1);
+    }
+    $i++;
+}
+
+if ($passwdfile ne ""){
+# Open file and get the password
+    unless (open (RPASS, $passwdfile)) {
+        die "Error, cannot open password file $passwdfile\n";
+    }
+    $passwd = <RPASS>;
+    chomp($passwd);
+    close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+    print "Bind Password: ";
+    # Disable console echo
+    system("@sttyexec@ -echo") if -t STDIN;
+    # read the answer
+    $passwd = <STDIN>;
+    # Enable console echo
+    system("@sttyexec@ echo") if -t STDIN;
+    print "\n";
+    chop($passwd); # trim trailing newline
+}
+
+if ( $rootdn eq "" || $passwd eq "" || $basedn eq "" || $rid eq "") 
+{ 
+    &usage; 
+    exit(1); 
+}
+
+$vstr = "";
+if ($verbose != 0) 
+{ 
+    $vstr = "-v"; 
+}
+
+# Use a timestamp as part of the task entry name
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+
+if($abort eq ""){
+    # Build the task entry to add
+    $taskname = "cleanallruv_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+    $dn = "dn: cn=$taskname, cn=cleanallruv, cn=tasks, cn=config\n";
+} else {
+    $taskname = "abort_cleanallruv_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+    $dn = "dn: cn=$taskname, cn=abort cleanallruv, cn=tasks, cn=config\n";
+}    
+$misc =   "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn =     "cn: $taskname\n";
+$basedn = "replica-base-dn: $basedn\n";
+$rid =    "replica-id: $rid\n";
+
+
+$entry = "${dn}${misc}${cn}${basedn}${rid}";
+open(FOO, "| ldapmodify @ldaptool_opts@ $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
+
+sub libpath_add {
+    my $libpath = shift;
+
+    if ($libpath) {
+        if ($ENV{'LD_LIBRARY_PATH'}) {
+            $ENV{'LD_LIBRARY_PATH'} = "$ENV{'LD_LIBRARY_PATH'}:$libpath";
+        } else {
+            $ENV{'LD_LIBRARY_PATH'} = "$libpath";
+        }
+    }
+}
+
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
index def693d..58b4b76 100644
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -134,15 +134,10 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2096 NAME 'entryusn' DESC 'Netscape defi
 attributeTypes: ( 2.16.840.1.113730.3.1.2113 NAME 'internalModifiersName' DESC 'plugin dn' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12  SINGLE-VALUE NO-USER-MODIFICATION  USAGE directoryOperation  X-ORIGIN '389 Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2114 NAME 'internalCreatorsName' DESC 'plugin dn' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12  SINGLE-VALUE NO-USER-MODIFICATION  USAGE directoryOperation  X-ORIGIN '389 Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2133 NAME 'pwdUpdateTime' DESC 'Last password update time' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE USAGE directoryOperation  X-ORIGIN '389 Directory Server' )
-attributeTypes: ( 2.16.840.1.113730.3.1.2111 NAME 'tombstoneNumSubordinates'
-  DESC 'count of immediate subordinates for tombstone entries'
-  EQUALITY integerMatch
-  ORDERING integerOrderingMatch
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
-  SINGLE-VALUE
-  NO-USER-MODIFICATION
-  USAGE directoryOperation
-  X-ORIGIN '389 directory server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2135 NAME 'nsds5ReplicaCleanRUV' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2136 NAME 'nsds5ReplicaCleanRUVNotified' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2137 NAME 'nsds5ReplicaAbortCleanRUV' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2111 NAME 'tombstoneNumSubordinates' DESC 'count of immediate subordinates for tombstone entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN '389 directory server' )
 #
 # objectclasses
 #
@@ -152,9 +147,9 @@ objectClasses: ( 2.16.840.1.113730.3.2.44 NAME 'nsIndex' DESC 'Netscape defined
 objectClasses: ( 2.16.840.1.113730.3.2.109 NAME 'nsBackendInstance' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top  MUST ( nsDS5ReplicaRoot $  nsDS5ReplicaId ) MAY (cn $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top  MUST ( nsDS5ReplicaRoot $  nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPName $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index 08bf771..a347c57 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -345,15 +345,15 @@ static int _cl5CheckMissingCSN (const CSN *minCsn, const RUV *supplierRUV, CL5DB
 static int _cl5TrimInit ();
 static void _cl5TrimCleanup ();
 static int _cl5TrimMain (void *param);
-static void _cl5DoTrimming ();
-static void _cl5TrimFile (Object *obj, long *numToTrim);
+static void _cl5DoTrimming (ReplicaId rid);
+static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid);
 static PRBool _cl5CanTrim (time_t time, long *numToTrim);
 static int  _cl5ReadRUV (const char *replGen, Object *obj, PRBool purge);
 static int  _cl5WriteRUV (CL5DBFile *file, PRBool purge);
 static int  _cl5ConstructRUV (const char *replGen, Object *obj, PRBool purge);
 static int  _cl5UpdateRUV (Object *obj, CSN *csn, PRBool newReplica, PRBool purge);
 static int  _cl5GetRUV2Purge2 (Object *fileObj, RUV **ruv);
-void trigger_cl_trimming_thread();
+void trigger_cl_trimming_thread(void *rid);
 
 /* bakup/recovery, import/export */
 static int _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op,
@@ -699,12 +699,12 @@ int cl5DeleteDBSync (Object *replica)
 }
 
 /* Name:        cl5GetUpperBoundRUV
-   Description: retrieves vector for that represnts the upper bound of the changes for a replica. 
+   Description: retrieves vector for that represents the upper bound of the changes for a replica.
    Parameters:  r - replica for which the purge vector is requested
                 ruv - contains a copy of the purge ruv if function is successful; 
-                unchanged otherwise. It is responsobility pf the caller to free
+                unchanged otherwise. It is responsibility of the caller to free
                 the ruv when it is no longer is in use
-   Return:      CL5_SUCCESS if function is successfull
+   Return:      CL5_SUCCESS if function is successful
                 CL5_BAD_STATE if the changelog is not initialized;
 				CL5_BAD_DATA - if NULL id is supplied
                 CL5_NOTFOUND, if changelog file for replica is not found
@@ -1682,6 +1682,16 @@ cl5GetNextOperationToReplay (CL5ReplayIterator *iterator, CL5Entry *entry)
 		return CL5_DB_ERROR;
 	}
 
+	if(is_cleaned_rid(csn_get_replicaid(csn))){
+		/*
+		 *  This operation is from a deleted replica.  During the cleanallruv task the
+		 *  replicas are cleaned first before this instance is.  This can cause the
+		 *  server to basically do a full update over and over.  So we have to watch for
+		 *  this, and not send these operations out.
+		 */
+		return CL5_IGNORE_OP;
+	}
+
 	/* there is an entry we should return */
 	/* Callers of this function should cl5_operation_parameters_done(op) */
 	if ( 0 != cl5DBData2Entry ( data, datalen, entry ) )
@@ -3383,7 +3393,7 @@ static int _cl5TrimMain (void *param)
 		{
 			/* time to trim */
 			timePrev = timeNow; 
-			_cl5DoTrimming ();
+			_cl5DoTrimming (0 /* there's no cleaned rid */);
 		}
 		if (NULL == s_cl5Desc.clLock)
 		{
@@ -3417,7 +3427,7 @@ static int _cl5TrimMain (void *param)
     
  */
 
-static void _cl5DoTrimming ()
+static void _cl5DoTrimming (ReplicaId rid)
 {
 	Object *obj;
 	long numToTrim;
@@ -3430,7 +3440,7 @@ static void _cl5DoTrimming ()
 	obj = objset_first_obj (s_cl5Desc.dbFiles);
 	while (obj && _cl5CanTrim ((time_t)0, &numToTrim))
 	{	
-		_cl5TrimFile (obj, &numToTrim);
+		_cl5TrimFile (obj, &numToTrim, rid);
 		obj = objset_next_obj (s_cl5Desc.dbFiles, obj);	
 	}
 
@@ -3447,12 +3457,13 @@ static void _cl5DoTrimming ()
 */
 #define CL5_TRIM_MAX_PER_TRANSACTION 10
 
-static void _cl5TrimFile (Object *obj, long *numToTrim)
+static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
 {
 	DB_TXN *txnid;
 	RUV *ruv = NULL;
 	CL5Entry entry;
 	slapi_operation_parameters op = {0};
+	ReplicaId csn_rid;
 	void *it;
 	int finished = 0, totalTrimmed = 0, count;
 	PRBool abort;
@@ -3476,7 +3487,6 @@ static void _cl5TrimFile (Object *obj, long *numToTrim)
 		count = 0;
 		txnid = NULL;
 		abort = PR_FALSE;
-		ReplicaId rid;
 
 		/* DB txn lock accessed pages until the end of the transaction. */
 		
@@ -3497,14 +3507,13 @@ static void _cl5TrimFile (Object *obj, long *numToTrim)
 			 * This change can be trimmed if it exceeds purge
 			 * parameters and has been seen by all consumers.
 			 */
-			rid = csn_get_replicaid (op.csn);
+			csn_rid = csn_get_replicaid (op.csn);
 			if ( (*numToTrim > 0 || _cl5CanTrim (entry.time, numToTrim)) &&
 				 ruv_covers_csn_strict (ruv, op.csn) )
 			{
 				rc = _cl5CurrentDeleteEntry (it);
-				if ( rc == CL5_SUCCESS && !is_released_rid(rid))
+				if ( rc == CL5_SUCCESS && cleaned_rid != csn_rid)
 				{
-					/* update purge vector, unless this is a released rid */
 					rc = _cl5UpdateRUV (obj, op.csn, PR_FALSE, PR_TRUE);				
 				}
 				if ( rc == CL5_SUCCESS)
@@ -3530,8 +3539,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim)
 				 * the trim forever.
 				 */
 				CSN *maxcsn = NULL;
-				rid = csn_get_replicaid (op.csn);
-				ruv_get_largest_csn_for_replica (ruv, rid, &maxcsn);
+				ruv_get_largest_csn_for_replica (ruv, csn_rid, &maxcsn);
 				if ( csn_compare (op.csn, maxcsn) != 0 )
 				{
 					/* op.csn is not anchor CSN */
@@ -3895,20 +3903,18 @@ static int _cl5UpdateRUV (Object *obj, CSN *csn, PRBool newReplica, PRBool purge
     /* update vector only if this replica is not yet part of RUV */
     if (purge && newReplica)
     {
-        if (ruv_contains_replica (file->purgeRUV, rid))
+        if (ruv_contains_replica (file->purgeRUV, rid)){
             return CL5_SUCCESS;
-        else if(!is_cleaned_rid(rid))
-        {
+        } else {
             /* if the replica is not part of the purgeRUV yet, add it unless it's from a cleaned rid */
             ruv_add_replica (file->purgeRUV, rid, multimaster_get_local_purl());
         }
     }
     else
     {
-        if (purge)
+        if (purge){
             rc = ruv_set_csns(file->purgeRUV, csn, NULL);
-        else if(!is_cleaned_rid(rid)){
-            /* don't update maxRuv if rid is cleaned */
+        } else {
             rc = ruv_set_csns(file->maxRUV, csn, NULL);
         }
     }
@@ -4520,17 +4526,9 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
 	CL5Entry entry;
 	CL5DBFile *file = NULL;
 	Object *file_obj = NULL;
-	ReplicaId rid = csn_get_replicaid (op->csn);
 	DB_TXN *txnid = NULL;
 	DB_TXN *parent_txnid = (DB_TXN *)txn;
 
-	/*
-	 *  If the op csn contains the cleaned rid, don't write it
-	 */
-	if(is_cleaned_rid(rid)){
-		return CL5_SUCCESS;
-	}
-
 	rc = _cl5GetDBFileByReplicaName (replName, replGen, &file_obj);
 	if (rc == CL5_NOTFOUND)
 	{
@@ -5089,7 +5087,7 @@ static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consum
 		 * legacy consumer. In this case the supplier
 		 * and the consumer may have the same RID.
 		 */
-		if (rid == consumerRID && rid != MAX_REPLICA_ID)
+		if ((rid == consumerRID && rid != MAX_REPLICA_ID) || (is_cleaned_rid(rid)) )
 			continue;
 
         startCSN = csns[i];
@@ -6556,13 +6554,12 @@ cl5CleanRUV(ReplicaId rid){
     }
 }
 
-void trigger_cl_trimming(){
+void trigger_cl_trimming(ReplicaId rid){
     PRThread *trim_tid = NULL;
-    ReplicaId rid = get_released_rid();
 
     slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "trigger_cl_trimming: rid (%d)\n",(int)rid);
     trim_tid = PR_CreateThread(PR_USER_THREAD, (VFP)(void*)trigger_cl_trimming_thread,
-                   NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+                   (void *)&rid, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
                    PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE);
     if (NULL == trim_tid){
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
@@ -6575,7 +6572,9 @@ void trigger_cl_trimming(){
 }
 
 void
-trigger_cl_trimming_thread(){
+trigger_cl_trimming_thread(void *arg){
+    ReplicaId rid = *(ReplicaId *)arg;
+
     /* make sure we have a change log, and we aren't closing it */
     if(s_cl5Desc.dbState == CL5_STATE_CLOSED || s_cl5Desc.dbState == CL5_STATE_CLOSING){
         return;
@@ -6585,6 +6584,6 @@ trigger_cl_trimming_thread(){
             "trigger_cl_trimming: failed to increment thread count "
             "NSPR error - %d\n", PR_GetError ());
     }
-    _cl5DoTrimming();
+    _cl5DoTrimming(rid);
     _cl5RemoveThread();
 }
diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h
index b9c3dd8..9b285ca 100644
--- a/ldap/servers/plugins/replication/cl5_api.h
+++ b/ldap/servers/plugins/replication/cl5_api.h
@@ -145,9 +145,10 @@ enum
 	CL5_CSN_ERROR,		/* CSN API failed */
 	CL5_RUV_ERROR,		/* RUV API failed */
 	CL5_OBJSET_ERROR,	/* namedobjset api failed */
-    CL5_PURGED_DATA,    /* requested data has been purged */
-    CL5_MISSING_DATA,   /* data should be in the changelog, but is missing */
-	CL5_UNKNOWN_ERROR	/* unclassified error */
+	CL5_PURGED_DATA,    /* requested data has been purged */
+	CL5_MISSING_DATA,   /* data should be in the changelog, but is missing */
+	CL5_UNKNOWN_ERROR,	/* unclassified error */
+	CL5_IGNORE_OP		/* ignore this updated - used by CLEANALLRUV task */
 };
 
 /***** Module APIs *****/
@@ -489,6 +490,6 @@ int cl5WriteRUV();
 int cl5DeleteRUV();
 void cl5CleanRUV(ReplicaId rid);
 void cl5NotifyCleanup(int rid);
-void trigger_cl_trimming();
+void trigger_cl_trimming(ReplicaId rid);
 
 #endif
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index d7ba6a6..fc756b1 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -94,10 +94,11 @@
  * new set of start and response extops. */
 #define REPL_START_NSDS90_REPLICATION_REQUEST_OID "2.16.840.1.113730.3.5.12"
 #define REPL_NSDS90_REPLICATION_RESPONSE_OID "2.16.840.1.113730.3.5.13"
-/* cleanruv/releaseruv extended ops */
+/* cleanallruv extended ops */
 #define REPL_CLEANRUV_OID "2.16.840.1.113730.3.6.5"
-#define REPL_RELEASERUV_OID "2.16.840.1.113730.3.6.6"
-
+#define REPL_ABORT_CLEANRUV_OID "2.16.840.1.113730.3.6.6"
+#define CLEANRUV_NOTIFIED 0
+#define CLEANRUV_RELEASED 1
 
 /* DS 5.0 replication protocol error codes */
 #define NSDS50_REPL_REPLICA_READY 0x00 /* Replica ready, go ahead */
@@ -157,6 +158,7 @@ extern const char *type_nsds5ReplicaBusyWaitTime;
 extern const char *type_nsds5ReplicaSessionPauseTime;
 extern const char *type_nsds5ReplicaEnabled;
 extern const char *type_nsds5ReplicaStripAttrs;
+extern const char *type_nsds5ReplicaCleanRUVnotified;
 
 /* Attribute names for windows replication agreements */
 extern const char *type_nsds7WindowsReplicaArea;
@@ -185,6 +187,8 @@ extern const char *type_replicaPurgeDelay;
 extern const char *type_replicaChangeCount;
 extern const char *type_replicaTombstonePurgeInterval;
 extern const char *type_replicaLegacyConsumer;
+extern const char *type_replicaCleanRUV;
+extern const char *type_replicaAbortCleanRUV;
 extern const char *type_ruvElementUpdatetime;
 
 /* multimaster plugin points */
@@ -224,7 +228,7 @@ char* get_repl_session_id (Slapi_PBlock *pb, char *id, CSN **opcsn);
 int multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb);
 int multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb);
 int multimaster_extop_cleanruv(Slapi_PBlock *pb);
-int multimaster_extop_releaseruv(Slapi_PBlock *pb);
+int multimaster_extop_abort_cleanruv(Slapi_PBlock *pb);
 int extop_noop(Slapi_PBlock *pb);
 struct berval *NSDS50StartReplicationRequest_new(const char *protocol_oid,
 	const char *repl_root, char **extra_referrals, CSN *csn);
@@ -359,6 +363,10 @@ PRBool agmt_is_enabled(Repl_Agmt *ra);
 int agmt_set_enabled_from_entry(Repl_Agmt *ra, Slapi_Entry *e);
 char **agmt_get_attrs_to_strip(Repl_Agmt *ra);
 int agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e);
+void agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e);
+int agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op);
+int agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid);
+int agmt_set_timeout(Repl_Agmt *ra, long timeout);
 
 typedef struct replica Replica;
 
@@ -369,7 +377,6 @@ void agmtlist_notify_all(Slapi_PBlock *pb);
 Object* agmtlist_get_first_agreement_for_replica (Replica *r);
 Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev);
 
-
 /* In repl5_backoff.c */
 typedef struct backoff_timer Backoff_Timer;
 #define BACKOFF_FIXED 1
@@ -443,6 +450,7 @@ ConnResult conn_read_result_ex(Repl_Connection *conn, char **retoidp, struct ber
 LDAP * conn_get_ldap(Repl_Connection *conn);
 void conn_lock(Repl_Connection *conn);
 void conn_unlock(Repl_Connection *conn);
+void conn_delete_internal_ext(Repl_Connection *conn);
 
 /* In repl5_protocol.c */
 typedef struct repl_protocol Repl_Protocol;
@@ -554,6 +562,9 @@ void replica_set_tombstone_reap_interval (Replica *r, long interval);
 void replica_update_ruv_consumer (Replica *r, RUV *supplier_ruv);
 void replica_set_ruv_dirty (Replica *r);
 void replica_write_ruv (Replica *r);
+char *replica_get_dn(Replica *r);
+void replica_check_for_tasks(Replica*r, Slapi_Entry *e);
+
 /* The functions below handles the state flag */
 /* Current internal state flags */
 /* The replica can be busy and not other flag, 
@@ -594,22 +605,40 @@ int replica_config_init();
 void replica_config_destroy ();
 int get_replica_type(Replica *r);
 int replica_execute_cleanruv_task_ext(Object *r, ReplicaId rid);
-void set_cleaned_rid(ReplicaId rid);
-void delete_cleaned_rid();
+void add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn);
 int is_cleaned_rid(ReplicaId rid);
-int get_released_rid();
-void set_released_rid(int rid);
-int is_released_rid(int rid);
-int is_already_released_rid();
-void delete_released_rid();
-void replica_cleanallruv_monitor_thread(void *arg);
+int replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+                               int *returncode, char *returntext, void *arg);
+void replica_cleanallruv_thread_ext(void *arg);
+void stop_ruv_cleaning();
+int task_aborted();
+void replica_abort_task_thread(void *arg);
+void delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn);
+int process_repl_agmts(Replica *replica, int *agmt_info, char *oid, Slapi_Task *task, struct berval *payload, int op);
+int decode_cleanruv_payload(struct berval *extop_value, char **payload);
+struct berval *create_ruv_payload(char *value);
+void replica_add_cleanruv_data(Replica *r, char *val);
+void replica_remove_cleanruv_data(Replica *r, char *val);
+CSN *replica_get_cleanruv_maxcsn(Replica *r, ReplicaId rid);
+void ruv_get_cleaned_rids(RUV *ruv, ReplicaId *rids);
+void add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root);
+int is_task_aborted(ReplicaId rid);
+void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root);
+void set_cleaned_rid(ReplicaId rid);
+void cleanruv_log(Slapi_Task *task, char *task_type, char *fmt, ...);
 
-#define ALREADY_RELEASED -1
+#define CLEANRIDSIZ 4 /* maximum number for concurrent CLEANALLRUV tasks */
 
 typedef struct _cleanruv_data
 {
 	Object *repl_obj;
+	Replica *replica;
 	ReplicaId rid;
+	Slapi_Task *task;
+	struct berval *payload;
+	CSN *maxcsn;
+	char *repl_root;
+	Slapi_DN *sdn;
 } cleanruv_data;
 
 /* replutil.c */
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 2978aba..5a16083 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -141,6 +141,7 @@ typedef struct repl5agmt {
 	char **attrs_to_strip; /* for fractional replication, if a "mod" is empty, strip out these attributes:
 	                        * modifiersname, modifytimestamp, internalModifiersname, internalModifyTimestamp, etc */
 	int agreement_type;
+	int cleanruv_notified[CLEANRIDSIZ + 1]; /* specifies if the replica has been notified of a CLEANALLRUV task */
 } repl5agmt;
 
 /* Forward declarations */
@@ -251,6 +252,7 @@ agmt_new_from_entry(Slapi_Entry *e)
 	Repl_Agmt *ra;
 	Slapi_Attr *sattr;
 	char *tmpstr;
+	char **clean_vals = NULL;
 	char **denied_attrs = NULL;
 	char *auto_initialize = NULL;
 	char *val_nsds5BeginReplicaRefresh = "start";
@@ -425,6 +427,19 @@ agmt_new_from_entry(Slapi_Entry *e)
 	ra->last_init_start_time = 0UL;
 	ra->last_init_status[0] = '\0';
 	
+	/* cleanruv notification */
+	clean_vals = slapi_entry_attr_get_charray(e, type_nsds5ReplicaCleanRUVnotified);
+	if(clean_vals){
+		int i;
+		for (i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
+			ra->cleanruv_notified[i] = atoi(clean_vals[i]);
+		}
+		ra->cleanruv_notified[i + 1] = 0;
+		slapi_ch_array_free(clean_vals);
+	} else {
+		ra->cleanruv_notified[0] = 0;
+	}
+
 	/* Fractional attributes */
 	slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeList, &sattr);
 
@@ -1685,6 +1700,20 @@ agmt_set_timeout_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
 	return return_value;
 }
 
+int
+agmt_set_timeout(Repl_Agmt *ra, long timeout)
+{
+    PR_Lock(ra->lock);
+    if (ra->stop_in_progress){
+        PR_Unlock(ra->lock);
+        return -1;
+    }
+    ra->timeout = timeout;
+    PR_Unlock(ra->lock);
+
+    return 0;
+}
+
 /*
  * Set or reset the busywaittime
  *
@@ -2571,3 +2600,84 @@ agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e)
 
     return -1;
 }
+
+int
+agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid){
+    int notified = 0;
+    int i;
+
+    PR_Lock(ra->lock);
+    for(i = 0; i < CLEANRIDSIZ && ra->cleanruv_notified[i]; i++){
+        if(ra->cleanruv_notified[i] == rid){
+            notified = 1;
+            break;
+        }
+    }
+    PR_Unlock(ra->lock);
+
+    return notified;
+}
+
+/*
+ *  This will trigger agmt_set_cleanruv_notified_from_entry() to be called,
+ *  which will update the in memory agmt.
+ *
+ *  op can be:  CLEANRUV_NOTIFIED or CLEANRUV_RELEASED
+ */
+int
+agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op){
+    Slapi_PBlock *pb;
+    LDAPMod *mods[2];
+    LDAPMod mod;
+    struct berval *vals[2];
+    struct berval val;
+    char data[6];
+    int rc = 0;
+
+    if(ra == NULL){
+        return -1;
+    }
+
+    if(op == CLEANRUV_NOTIFIED){
+        /* add the cleanruv data */
+    	mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
+    } else {
+        /* remove the cleanruv data */
+    	mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
+    }
+
+    pb = slapi_pblock_new();
+    val.bv_len = PR_snprintf(data, sizeof(data), "%d", (int)rid);
+    mod.mod_type = (char *)type_nsds5ReplicaCleanRUVnotified;
+    mod.mod_bvalues = vals;
+    vals [0] = &val;
+    vals [1] = NULL;
+    val.bv_val = data;
+    mods[0] = &mod;
+    mods[1] = NULL;
+
+    slapi_modify_internal_set_pb_ext (pb, ra->dn, mods, NULL, NULL,
+        repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+    slapi_modify_internal_pb (pb);
+    slapi_pblock_destroy(pb);
+
+    return rc;
+}
+
+void
+agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e){
+    char **attr_vals = NULL;
+    int i;
+
+    PR_Lock(ra->lock);
+    attr_vals = slapi_entry_attr_get_charray(e, type_nsds5ReplicaCleanRUVnotified);
+    if(attr_vals){
+        for (i = 0; i < CLEANRIDSIZ && attr_vals[i]; i++){
+            ra->cleanruv_notified[i] = atoi(attr_vals[i]);
+        }
+        ra->cleanruv_notified[i + 1] = 0;
+    } else {
+        ra->cleanruv_notified[0] = 0;
+    }
+    PR_Unlock(ra->lock);
+}
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index 86f06bf..c0b9664 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -508,6 +508,10 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
                 rc = SLAPI_DSE_CALLBACK_ERROR;
             }
         }
+        else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaCleanRUVnotified))
+        {
+            agmt_set_cleanruv_notified_from_entry(agmt, e);
+        }
         else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
         {
             slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " 
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
index 5fdc601..51a2bc5 100644
--- a/ldap/servers/plugins/replication/repl5_connection.c
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -140,7 +140,7 @@ static void repl5_debug_timeout_callback(time_t when, void *arg);
 static void close_connection_internal(Repl_Connection *conn);
 
 /*
- * Create a new conenction object. Returns a pointer to the object, or
+ * Create a new connection object. Returns a pointer to the object, or
  * NULL if an error occurs.
  */
 Repl_Connection *
@@ -217,6 +217,17 @@ conn_delete_internal(Repl_Connection *conn)
 }
 
 /*
+ *  Used by CLEANALLRUV - free it all!
+ */
+void
+conn_delete_internal_ext(Repl_Connection *conn)
+{
+    conn_delete_internal(conn);
+    PR_DestroyLock(conn->lock);
+    slapi_ch_free((void **)&conn);
+}
+
+/*
  * Destroy a connection. It is an error to use the connection object
  * after conn_delete() has been called.
  */
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 7388d62..025c23f 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -466,7 +466,7 @@ repl5_inc_waitfor_async_results(result_data *rd)
 	int done = 0;
 	int loops = 0;
 	/* Keep pulling results off the LDAP connection until we catch up to the last message id stored in the rd */
-	while (!done) 
+	while (!done && !slapi_is_shutting_down())
 	{
 		/* Lock the structure to force memory barrier */
 		PR_Lock(rd->lock);
@@ -1473,10 +1473,10 @@ repl5_inc_update_from_op_result(Private_Repl_Protocol *prp, ConnResult replay_cr
 							agmt_inc_last_update_changecount (prp->agmt, replica_id, 1 /*skipped*/);
 						}
 						slapi_log_error(*finished ? SLAPI_LOG_FATAL : slapi_log_urp, repl_plugin_name,
-							"%s: Consumer failed to replay change (uniqueid %s, CSN %s): %s. %s.\n",
+							"%s: Consumer failed to replay change (uniqueid %s, CSN %s): %s (%d). %s.\n",
 							agmt_get_long_name(prp->agmt),
 							uniqueid, csn_str,
-							ldap_err2string(connection_error),
+							ldap_err2string(connection_error), connection_error,
 							*finished ? "Will retry later" : "Skipping");
 					}
 					else if (CONN_NOT_CONNECTED == replay_crc)
@@ -1487,10 +1487,11 @@ repl5_inc_update_from_op_result(Private_Repl_Protocol *prp, ConnResult replay_cr
 						*finished = 1;
 						slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 							"%s: Consumer failed to replay change (uniqueid %s, CSN %s): "
-							"%s. Will retry later.\n",
+							"%s(%d). Will retry later.\n",
 							agmt_get_long_name(prp->agmt),
 							uniqueid, csn_str,
-							connection_error ? ldap_err2string(connection_error) : "Connection lost");
+							connection_error ? ldap_err2string(connection_error) : "Connection lost",
+							connection_error);
 					}
 					else if (CONN_TIMEOUT == replay_crc)
 					{
@@ -1533,7 +1534,7 @@ repl5_inc_update_from_op_result(Private_Repl_Protocol *prp, ConnResult replay_cr
  * has already been acquired, (2) that the consumer's update vector has
  * been checked and (3) that it's ok to send incremental updates.
  * Returns:
- * UPDATE_NO_MORE_UPDATES - all updates were sent succussfully
+ * UPDATE_NO_MORE_UPDATES - all updates were sent successfully
  * UPDATE_TRANSIENT_ERROR - some non-permanent error occurred. Try again later.
  * UPDATE_FATAL_ERROR - some bad, permanent error occurred.
  * UPDATE_SCHEDULE_WINDOW_CLOSED - the schedule window closed on us.
@@ -1603,7 +1604,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 				agmt_get_long_name(prp->agmt));
 			return_value = UPDATE_FATAL_ERROR;
 			break;
-		case CL5_SYSTEM_ERROR:   /* NSPR error occurred: use PR_GetError for furhter info */
+		case CL5_SYSTEM_ERROR:   /* NSPR error occurred: use PR_GetError for further info */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: An NSPR error (%d) occurred\n",
 				agmt_get_long_name(prp->agmt), PR_GetError());
@@ -1642,7 +1643,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 			break;
 		case CL5_UNKNOWN_ERROR:   /* unclassified error */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-				"%s: An unknown error was ecountered\n",
+				"%s: An unknown error was encountered\n",
 				agmt_get_long_name(prp->agmt));
 			return_value = UPDATE_TRANSIENT_ERROR;
 			break;
@@ -1834,6 +1835,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 					agmt_get_long_name(prp->agmt));
 				return_value = UPDATE_FATAL_ERROR;
 				break;
+			case CL5_IGNORE_OP:
+				break;
 			default:
 				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 					"%s: Unknown error code (%d) returned from cl5GetNextOperationToReplay\n",
@@ -1865,7 +1868,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 		/* Terminate the results reading thread */
 		if (!prp->repl50consumer) 
 		{
-			/* We need to ensure that we wait until all the responses have been recived from our operations */
+			/* We need to ensure that we wait until all the responses have been received from our operations */
 			if (return_value != UPDATE_CONNECTION_LOST) {
 				/* if connection was lost/closed, there will be nothing to read */
 				repl5_inc_waitfor_async_results(rd);
diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c
index a878b19..7a80c6f 100644
--- a/ldap/servers/plugins/replication/repl5_init.c
+++ b/ldap/servers/plugins/replication/repl5_init.c
@@ -126,12 +126,12 @@ static char *cleanruv_name_list[] = {
 		NSDS_REPL_NAME_PREFIX " Cleanruv",
 		NULL
 };
-static char *releaseruv_oid_list[] = {
-		REPL_RELEASERUV_OID,
+static char *cleanruv_abort_oid_list[] = {
+		REPL_ABORT_CLEANRUV_OID,
 		NULL
 };
-static char *releaseruv_name_list[] = {
-		NSDS_REPL_NAME_PREFIX " Releaseruv",
+static char *cleanruv_abort_name_list[] = {
+		NSDS_REPL_NAME_PREFIX " Cleanruv Abort",
 		NULL
 };
 
@@ -474,7 +474,7 @@ multimaster_cleanruv_extop_init( Slapi_PBlock *pb )
 }
 
 int
-multimaster_releaseruv_extop_init( Slapi_PBlock *pb )
+multimaster_cleanruv_abort_extop_init( Slapi_PBlock *pb )
 {
 	int rc= 0; /* OK */
 	void *identity = NULL;
@@ -485,11 +485,11 @@ multimaster_releaseruv_extop_init( Slapi_PBlock *pb )
 
 	if (slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
 		slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
-		slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)releaseruv_oid_list ) != 0  ||
-		slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)releaseruv_name_list ) != 0  ||
-		slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_releaseruv ))
+		slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)cleanruv_abort_oid_list ) != 0  ||
+		slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)cleanruv_abort_name_list ) != 0  ||
+		slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_abort_cleanruv ))
 	{
-		slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_releaseruv_extop_init failed\n" );
+		slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_cleanruv_abort_extop_init failed\n" );
 		rc= -1;
 	}
 
@@ -605,24 +605,22 @@ multimaster_stop( Slapi_PBlock *pb )
     int rc= 0; /* OK */
 
     if (!multimaster_stopped_flag)
-	{
-		if (!is_ldif_dump)
-		{
-			agmtlist_shutdown(); /* Shut down replication agreements */
-		}
-
+    {
+        if (!is_ldif_dump)
+        {
+            /* Shut down replication agreements */
+            agmtlist_shutdown();
+        }
+        /* if we are cleaning a ruv, stop */
+        stop_ruv_cleaning();
         /* unregister backend state change notification */
         slapi_unregister_backend_state_change((void *)multimaster_be_state_change);
-
-		changelog5_cleanup(); /* Shut down the changelog */
-		multimaster_mtnode_extension_destroy(); /* Destroy mapping tree node exts */
+        changelog5_cleanup(); /* Shut down the changelog */
+        multimaster_mtnode_extension_destroy(); /* Destroy mapping tree node exts */
         replica_destroy_name_hash(); /* destroy the hash and its remaining content */
         replica_config_destroy (); /* Destroy replica config info */
-    	multimaster_stopped_flag = 1;
-		/* JCMREPL - Wait for all our threads to stop */
-		/* JCMREPL - Shut down the replication plugin */
-		/* JCMREPL - Mark all the replication plugin interfaces at not enabled. */
-	}
+        multimaster_stopped_flag = 1;
+    }
     return rc;
 }
 
@@ -680,7 +678,7 @@ int replication_multimaster_plugin_init(Slapi_PBlock *pb)
 		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_total_extop_init", multimaster_total_extop_init, "Multimaster replication total update extended operation plugin", NULL, identity);
 		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_response_extop_init", multimaster_response_extop_init, "Multimaster replication extended response plugin", NULL, identity);
 		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_cleanruv_extop_init", multimaster_cleanruv_extop_init, "Multimaster replication cleanruv extended operation plugin", NULL, identity);
-		rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_releaseruv_extop_init", multimaster_releaseruv_extop_init, "Multimaster replication releaserid extended response plugin", NULL, identity);
+		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);
 		if (0 == rc)
 		{
 			multimaster_initialised = 1;
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
index 5ca6d90..964dd88 100644
--- a/ldap/servers/plugins/replication/repl5_plugins.c
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
@@ -1010,15 +1010,6 @@ write_changelog_and_ruv (Slapi_PBlock *pb)
 	r = (Replica*)object_get_data (repl_obj);
 	PR_ASSERT (r);
 
-	/*
-	 *  In case we had to run cleanruv, we don't want to continue to write
-	 *  updates to the changelog/database ruv from that replica(rid).
-	 */
-	if( is_cleaned_rid(replica_get_rid(r))){
-		/* this RID has been cleaned, just goto done */
-		goto done;
-	}
-
 	if (replica_is_flag_set (r, REPLICA_LOG_CHANGES) &&
 		(cl5GetState () == CL5_STATE_OPEN))
 	{
@@ -1073,6 +1064,12 @@ write_changelog_and_ruv (Slapi_PBlock *pb)
 			op_params->target_address.uniqueid = slapi_ch_strdup (uniqueid);
 		} 
 
+		if( is_cleaned_rid(csn_get_replicaid(op_params->csn))){
+			/* this RID has been cleaned */
+			object_release (repl_obj);
+			return 0;
+		}
+
 		/* we might have stripped all the mods - in that case we do not
 		   log the operation */
 		if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
@@ -1125,7 +1122,6 @@ write_changelog_and_ruv (Slapi_PBlock *pb)
 		update_ruv_component(r, opcsn, pb);
 	}
 
-done:
 	object_release (repl_obj);
 	return return_value;
 }
@@ -1328,7 +1324,7 @@ process_operation (Slapi_PBlock *pb, const CSN *csn)
     ruv = (RUV*)object_get_data (ruv_obj);
     PR_ASSERT (ruv);
  
-    rc = ruv_add_csn_inprogress (ruv, csn);    
+    rc = ruv_add_csn_inprogress (ruv, csn);
 
     object_release (ruv_obj);
     object_release (r_obj);
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index ccaa29d..27cdacd 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -61,20 +61,20 @@
  */
 struct replica {
 	Slapi_DN *repl_root;			/* top of the replicated area			*/
-    char *repl_name;                /* unique replica name                  */
-    PRBool new_name;                /* new name was generated - need to be saved */
+	char *repl_name;                /* unique replica name                  */
+	PRBool new_name;                /* new name was generated - need to be saved */
 	ReplicaUpdateDNList updatedn_list;	/* list of dns with which a supplier should bind
 										   to update this replica				*/
 	ReplicaType	 repl_type;			/* is this replica read-only ?			*/
-    PRBool  legacy_consumer;        /* if true, this replica is supplied by 4.0 consumer */
-    char*   legacy_purl;            /* partial url of the legacy supplier   */
+	PRBool  legacy_consumer;        /* if true, this replica is supplied by 4.0 consumer */
+	char*   legacy_purl;            /* partial url of the legacy supplier   */
 	ReplicaId repl_rid;				/* replicaID							*/
 	Object	*repl_ruv;				/* replica update vector				*/
 	PRBool repl_ruv_dirty;          /* Dirty flag for ruv                   */
 	CSNPL *min_csn_pl;              /* Pending list for minimal CSN         */
 	void *csn_pl_reg_id;            /* registration assignment for csn callbacks */
 	unsigned long repl_state_flags;	/* state flags							*/
-    PRUint32    repl_flags;         /* persistent, externally visible flags */
+	PRUint32    repl_flags;         /* persistent, externally visible flags */
 	PRLock	*repl_lock;				/* protects entire structure			*/
 	Slapi_Eq_Context repl_eqcxt_rs;	/* context to cancel event that saves ruv */	
 	Slapi_Eq_Context repl_eqcxt_tr;	/* context to cancel event that reaps tombstones */	
@@ -85,9 +85,10 @@ struct replica {
 	PRBool tombstone_reap_active;	/* TRUE when the tombstone reaper is running */
 	long tombstone_reap_interval; /* Time in seconds between tombstone reaping */
 	Slapi_ValueSet *repl_referral;  /* A list of administrator provided referral URLs */
-    PRBool state_update_inprogress; /* replica state is being updated */
-    PRLock *agmt_lock;          /* protects agreement creation, start and stop */
+	PRBool state_update_inprogress; /* replica state is being updated */
+	PRLock *agmt_lock;          /* protects agreement creation, start and stop */
 	char *locking_purl;			/* supplier who has exclusive access */
+	char *repl_cleanruv_data[CLEANRIDSIZ + 1];
 };
 
 
@@ -123,6 +124,7 @@ static int replica_log_ruv_elements_nolock (const Replica *r);
 static void replica_replace_ruv_tombstone(Replica *r);
 static void start_agreements_for_replica (Replica *r, PRBool start);
 static void _delete_tombstone(const char *tombstone_dn, const char *uniqueid, int ext_op_flags);
+static void replica_strip_cleaned_rids(Replica *r);
 
 /* Allocates new replica and reads its state and state of its component from
  * various parts of the DIT. 
@@ -270,6 +272,8 @@ replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation
                         slapi_sdn_get_dn(r->repl_root));
     }
 
+    replica_check_for_tasks(r, e);
+
 done:
     if (rc != 0 && r)
 	{
@@ -306,6 +310,7 @@ replica_destroy(void **arg)
 {
 	Replica *r;
 	void *repl_name;
+	int i;
 
 	if (arg == NULL)
 		return;
@@ -392,6 +397,10 @@ replica_destroy(void **arg)
 		csnplFree(&r->min_csn_pl);;
 	}
 
+	for(i = 0;r->repl_cleanruv_data[i] != NULL; i++){
+		slapi_ch_free_string(&r->repl_cleanruv_data[i]);
+	}
+
 	slapi_ch_free((void **)arg);
 }
 
@@ -1302,7 +1311,7 @@ replica_reload_ruv (Replica *r)
     }
 
     /* check if there is a changelog and whether this replica logs changes */
-    if (cl5GetState () == CL5_STATE_OPEN && r->repl_flags & REPLICA_LOG_CHANGES)
+    if (cl5GetState () == CL5_STATE_OPEN && (r->repl_flags & REPLICA_LOG_CHANGES))
     {
 
         /* Compare new ruv to the changelog's upper bound ruv. We could only keep
@@ -1424,7 +1433,7 @@ int replica_check_for_data_reload (Replica *r, void *arg)
     PR_ASSERT (r);
 
     /* check that we have a changelog and if this replica logs changes */
-    if (cl5GetState () == CL5_STATE_OPEN && r->repl_flags & REPLICA_LOG_CHANGES)
+    if (cl5GetState () == CL5_STATE_OPEN && (r->repl_flags & REPLICA_LOG_CHANGES))
     {
         /* Compare new ruv to the purge ruv. If the new contains csns which
            are smaller than those in purge ruv, we need to remove old and
@@ -1558,6 +1567,12 @@ _replica_get_config_entry (const Slapi_DN *root)
 	return e; 
 }
 
+char *
+replica_get_dn(Replica *r)
+{
+    return _replica_get_config_dn (r->repl_root);
+}
+
 static int 
 _replica_check_validity (const Replica *r)
 {
@@ -1785,6 +1800,177 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
     return (_replica_check_validity (r));
 }
 
+void
+replica_check_for_tasks(Replica *r, Slapi_Entry *e)
+{
+    char **clean_vals;
+
+    if(e == NULL){
+        return;
+    }
+    /*
+     *  check if we are in the middle of a CLEANALLRUV task,
+     *  if so set the cleaned rid, and fire off the thread
+     */
+    if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaCleanRUV)) != NULL)
+    {
+        PRThread *thread = NULL;
+        struct berval *payload = NULL;
+        CSN *maxcsn = NULL;
+        char *csnpart;
+        char *iter;
+        char csnstr[CSN_STRSIZE];
+        char *ridstr;
+        char *token = NULL;
+        ReplicaId rid;
+        int i;
+
+        for(i = 0; clean_vals[i]; i++){
+            cleanruv_data *data = NULL;
+
+            /*
+             *  Set the cleanruv data, and add the cleaned rid
+             */
+            r->repl_cleanruv_data[i] = slapi_ch_strdup(clean_vals[i]);
+            token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
+            if(token){
+                rid = atoi(token);
+                if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
+                    slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: invalid replica id(%d) "
+                       "aborting task.\n", rid);
+                    goto done;
+                }
+            } else {
+                slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: unable to parse cleanallruv "
+                    "data (%s), aborting task.\n",clean_vals[i]);
+                goto done;
+            }
+            csnpart = ldap_utf8strtok_r(iter, ":", &iter);
+            maxcsn = csn_new();
+            csn_init_by_string(maxcsn, csnpart);
+            csn_as_string(maxcsn, PR_FALSE, csnstr);
+            add_cleaned_rid(rid, r, csnstr);
+
+            slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: cleanAllRUV task found, "
+                "resuming the cleaning of rid(%d)...\n", rid);
+            /*
+             *  Create payload
+             */
+            ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr);
+            payload = create_ruv_payload(ridstr);
+            slapi_ch_free_string(&ridstr);
+
+            if(payload == NULL){
+                slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: Startup: Failed to "
+                    "create extended op payload, aborting task");
+                return;
+            }
+            /*
+             *  Setup the data struct, and fire off the thread.
+             */
+            data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
+            if (data == NULL) {
+                slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV: failed to allocate cleanruv_data.\n");
+                csn_free(&maxcsn);
+            } else {
+                /* setup our data */
+                data->repl_obj = NULL;
+                data->replica = NULL;
+                data->rid = rid;
+                data->task = NULL;
+                data->maxcsn = maxcsn;
+                data->sdn = slapi_sdn_dup(r->repl_root);
+                data->payload = payload;
+
+                thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
+                        (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+                        PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+                if (thread == NULL) {
+                    slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV: unable to create cleanAllRUV "
+                        "thread for rid(%d)\n", (int)data->rid);
+                }
+            }
+        }
+        r->repl_cleanruv_data[i] = NULL;
+    }
+
+    if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaAbortCleanRUV)) != NULL)
+    {
+        PRThread *thread = NULL;
+        struct berval *payload;
+        CSN *maxcsn = NULL;
+        char *iter;
+        char *ridstr = NULL;
+        char *repl_root;
+        char *token = NULL;
+        ReplicaId rid;
+        int i;
+
+        for(i = 0; clean_vals[i]; i++){
+            cleanruv_data *data = NULL;
+
+            token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
+            if(token){
+                rid = atoi(token);
+                if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
+                    slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: invalid replica id(%d) "
+                        "aborting task.\n", rid);
+                    goto done;
+                }
+            } else {
+                slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to parse cleanallruv "
+                    "data (%s), aborting task.\n",clean_vals[i]);
+                goto done;
+            }
+
+            repl_root = ldap_utf8strtok_r(iter, ":", &iter);
+            stop_ruv_cleaning();
+            maxcsn = replica_get_cleanruv_maxcsn(r, rid);
+            delete_cleaned_rid(r, rid, maxcsn);
+            csn_free(&maxcsn);
+
+            slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: abort task found, "
+                "resuming abort of rid(%d).\n", rid);
+            /*
+             *  Setup the data struct, and fire off the abort thread.
+             */
+            data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
+            if (data == NULL) {
+                slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to allocate cleanruv_data.\n");
+            } else {
+                ridstr = slapi_ch_smprintf("%d:%s", rid, repl_root);
+                payload = create_ruv_payload(ridstr);
+                slapi_ch_free_string(&ridstr);
+
+                if(payload == NULL){
+                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to create extended "
+                        "op payload\n");
+                } else {
+                    /* setup the data */
+                    data->repl_obj = NULL;
+                    data->replica = NULL;
+                    data->rid = rid;
+                    data->task = NULL;
+                    data->payload = payload;
+                    data->repl_root = slapi_ch_strdup(repl_root);
+                    data->sdn = slapi_sdn_dup(r->repl_root);
+
+                    thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
+                            (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+                            PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+                    if (thread == NULL) {
+                        slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to create abort cleanAllRUV "
+                            "thread for rid(%d)\n", (int)data->rid);
+                    }
+                }
+            }
+        }
+    }
+
+done:
+    slapi_ch_array_free(clean_vals);
+}
+
 /* This function updates the entry to contain information generated 
    during replica initialization.
    Returns 0 if successful and -1 otherwise */
@@ -2782,26 +2968,25 @@ static const char *root_glue =
 static int
 replica_create_ruv_tombstone(Replica *r)
 {
-	int return_value = LDAP_LOCAL_ERROR;
-	char *root_entry_str;
-	Slapi_Entry *e = NULL;
+    int return_value = LDAP_LOCAL_ERROR;
+    char *root_entry_str;
+    Slapi_Entry *e = NULL;
     const char *purl = NULL;
     RUV *ruv;
     struct berval **bvals = NULL;
     Slapi_PBlock *pb = NULL;
     int rc;
 	
-	PR_ASSERT(NULL != r && NULL != r->repl_root);
-	root_entry_str = slapi_ch_smprintf(root_glue, slapi_sdn_get_ndn(r->repl_root),
-		RUV_STORAGE_ENTRY_UNIQUEID);
+    PR_ASSERT(NULL != r && NULL != r->repl_root);
 
-	e = slapi_str2entry(root_entry_str, SLAPI_STR2ENTRY_TOMBSTONE_CHECK);
+    root_entry_str = slapi_ch_smprintf(root_glue, slapi_sdn_get_ndn(r->repl_root), RUV_STORAGE_ENTRY_UNIQUEID);
+
+    e = slapi_str2entry(root_entry_str, SLAPI_STR2ENTRY_TOMBSTONE_CHECK);
     if (e == NULL)
         goto done;
 
     /* Add ruv */
-    if (r->repl_ruv == NULL)
-    {
+    if (r->repl_ruv == NULL){
         CSNGen *gen;
         CSN *csn;
         char csnstr [CSN_STRSIZE];
@@ -2810,42 +2995,34 @@ replica_create_ruv_tombstone(Replica *r)
         gen = (CSNGen *)object_get_data(r->repl_csngen);
         PR_ASSERT (gen);
 
-        if (csngen_new_csn(gen, &csn, PR_FALSE /* notify */) == CSN_SUCCESS)
-		{
-			(void)csn_as_string(csn, PR_FALSE, csnstr);
-			csn_free(&csn);
+        if (csngen_new_csn(gen, &csn, PR_FALSE /* notify */) == CSN_SUCCESS){
+            (void)csn_as_string(csn, PR_FALSE, csnstr);
+            csn_free(&csn);
 
-			/* if this is an updateable replica - add its own
-			   element to the RUV so that referrals work correctly */
-			if (r->repl_type == REPLICA_TYPE_UPDATABLE)
-				purl = multimaster_get_local_purl();
+            /*
+             * if this is an updateable replica - add its own
+             * element to the RUV so that referrals work correctly
+             */
+            if (r->repl_type == REPLICA_TYPE_UPDATABLE)
+                purl = multimaster_get_local_purl();
 
-			if (ruv_init_new(csnstr, r->repl_rid, purl, &ruv) == RUV_SUCCESS)
-			{
-				r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
-				r->repl_ruv_dirty = PR_TRUE;
-				return_value = LDAP_SUCCESS;
-			}
-			else
-			{
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
-								"Cannot create new replica update vector for %s\n",
-								slapi_sdn_get_dn(r->repl_root));
-				ruv_destroy(&ruv);
+            if (ruv_init_new(csnstr, r->repl_rid, purl, &ruv) == RUV_SUCCESS){
+                r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
+                r->repl_ruv_dirty = PR_TRUE;
+                return_value = LDAP_SUCCESS;
+            } else {
+                slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Cannot create new replica update vector for %s\n",
+                    slapi_sdn_get_dn(r->repl_root));
+                ruv_destroy(&ruv);
                 goto done;
-			}
-		}
-		else
-		{
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-							"Cannot obtain CSN for new replica update vector for %s\n",
-							slapi_sdn_get_dn(r->repl_root));
-			csn_free(&csn);
+            }
+        } else {
+            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Cannot obtain CSN for new replica update vector for %s\n",
+                slapi_sdn_get_dn(r->repl_root));
+            csn_free(&csn);
             goto done;
-		}
-	}
-    else  /* failed to write the entry because DB was not initialized - retry */
-    {
+        }
+    } else { /* failed to write the entry because DB was not initialized - retry */
         ruv = (RUV*) object_get_data (r->repl_ruv);
         PR_ASSERT (ruv);
     }
@@ -2853,30 +3030,22 @@ replica_create_ruv_tombstone(Replica *r)
     PR_ASSERT (r->repl_ruv);
 
     rc = ruv_to_bervals(ruv, &bvals);
-    if (rc != RUV_SUCCESS)
-    {
+    if (rc != RUV_SUCCESS){
         goto done;
     }
         
     /* ONREPL this is depricated function but there is currently no better API to use */
     rc = slapi_entry_add_values(e, type_ruvElement, bvals);
-    if (rc != 0)
-    {
+    if (rc != 0){
         goto done;
     }        
-    
 
-	pb = slapi_pblock_new();
-	slapi_add_entry_internal_set_pb(
-		pb,
-		e,
-		NULL /* controls */,
-		repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
-		OP_FLAG_TOMBSTONE_ENTRY | OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP |
-		OP_FLAG_REPL_RUV);
-	slapi_add_internal_pb(pb);
-	e = NULL; /* add consumes e, upon success or failure */
-	slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
+    pb = slapi_pblock_new();
+    slapi_add_entry_internal_set_pb(pb, e, NULL /* controls */,	repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+        OP_FLAG_TOMBSTONE_ENTRY | OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | OP_FLAG_REPL_RUV);
+    slapi_add_internal_pb(pb);
+    e = NULL; /* add consumes e, upon success or failure */
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
     if (return_value == LDAP_SUCCESS)
         r->repl_ruv_dirty = PR_FALSE;
 		
@@ -2889,50 +3058,50 @@ done:
     if (pb)
         slapi_pblock_destroy(pb);
 
-	slapi_ch_free((void **) &root_entry_str);
+    slapi_ch_free_string(&root_entry_str);
 
-	return return_value;
+    return return_value;
 }
 
 
 static void
 assign_csn_callback(const CSN *csn, void *data)
 {
-	Replica *r = (Replica *)data;
+    Replica *r = (Replica *)data;
     Object *ruv_obj;
     RUV *ruv;
 
-	PR_ASSERT(NULL != csn);
-	PR_ASSERT(NULL != r);
+    PR_ASSERT(NULL != csn);
+    PR_ASSERT(NULL != r);
 
     ruv_obj = replica_get_ruv (r);
     PR_ASSERT (ruv_obj);
     ruv = (RUV*)object_get_data (ruv_obj);
     PR_ASSERT (ruv);
 
-	PR_Lock(r->repl_lock);
+    PR_Lock(r->repl_lock);
 
-	r->repl_csn_assigned = PR_TRUE;
+    r->repl_csn_assigned = PR_TRUE;
 	
-	if (NULL != r->min_csn_pl)
-	{
-		if (csnplInsert(r->min_csn_pl, csn) != 0)
-		{
-			char csn_str[CSN_STRSIZE]; /* For logging only */
-			/* Ack, we can't keep track of min csn. Punt. */
-			if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
-				slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "assign_csn_callback: "
-								"failed to insert csn %s for replica %s\n",
-								csn_as_string(csn, PR_FALSE, csn_str),
-								slapi_sdn_get_dn(r->repl_root));
-			}
-			csnplFree(&r->min_csn_pl);
-		}
-	}
+    if (NULL != r->min_csn_pl)
+    {
+        if (csnplInsert(r->min_csn_pl, csn) != 0)
+        {
+            char csn_str[CSN_STRSIZE]; /* For logging only */
+            /* Ack, we can't keep track of min csn. Punt. */
+            if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+                slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "assign_csn_callback: "
+                    "failed to insert csn %s for replica %s\n",
+                    csn_as_string(csn, PR_FALSE, csn_str),
+                    slapi_sdn_get_dn(r->repl_root));
+            }
+            csnplFree(&r->min_csn_pl);
+        }
+    }
 
     ruv_add_csn_inprogress (ruv, csn);
 
-	PR_Unlock(r->repl_lock);
+    PR_Unlock(r->repl_lock);
 
     object_release (ruv_obj);
 }
@@ -3167,19 +3336,41 @@ replica_set_tombstone_reap_interval (Replica *r, long interval)
 	PR_Unlock(r->repl_lock);
 }
 
+static void
+replica_strip_cleaned_rids(Replica *r)
+{
+    Object *RUVObj;
+    RUV *ruv = NULL;
+    ReplicaId rid[32] = {0};
+    int i = 0;
+
+    RUVObj = replica_get_ruv(r);
+    ruv =  (RUV*)object_get_data (RUVObj);
+
+    ruv_get_cleaned_rids(ruv, rid);
+    while(rid[i] != 0){
+        ruv_delete_replica(ruv, rid[i]);
+        replica_set_ruv_dirty(r);
+        replica_write_ruv(r);
+        i++;
+    }
+    object_release(RUVObj);
+}
+
 /* Update the tombstone entry to reflect the content of the ruv */
 static void
 replica_replace_ruv_tombstone(Replica *r)
 {
     Slapi_PBlock *pb = NULL;
-	char *dn;
-	int rc;
-
     Slapi_Mod smod;
     Slapi_Mod smod_last_modified;
     LDAPMod *mods [3];
+    char *dn;
+    int rc;
+
+    PR_ASSERT(NULL != r && NULL != r->repl_root);
 
-	PR_ASSERT(NULL != r && NULL != r->repl_root);
+    replica_strip_cleaned_rids(r);
 
     PR_Lock(r->repl_lock);
 
@@ -3188,14 +3379,14 @@ replica_replace_ruv_tombstone(Replica *r)
     ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified);
 
     dn = _replica_get_config_dn (r->repl_root);
-	if (NULL == dn) {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-			"replica_replace_ruv_tombstone: "
-			"failed to get the config dn for %s\n",
-			slapi_sdn_get_dn (r->repl_root));
-		PR_Unlock(r->repl_lock);
-		goto bail;
-	}
+    if (NULL == dn) {
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+            "replica_replace_ruv_tombstone: "
+            "failed to get the config dn for %s\n",
+            slapi_sdn_get_dn (r->repl_root));
+        PR_Unlock(r->repl_lock);
+        goto bail;
+    }
     mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod);
     mods[1] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod_last_modified);
 
@@ -3219,12 +3410,12 @@ replica_replace_ruv_tombstone(Replica *r)
 
     if (rc != LDAP_SUCCESS)
     {
-		if ((rc != LDAP_NO_SUCH_OBJECT) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
-		{
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: "
-				"failed to update replication update vector for replica %s: LDAP "
-							"error - %d\n", (char*)slapi_sdn_get_dn (r->repl_root), rc);
-		}
+        if ((rc != LDAP_NO_SUCH_OBJECT) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
+        {
+            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: "
+                "failed to update replication update vector for replica %s: LDAP "
+                "error - %d\n", (char*)slapi_sdn_get_dn (r->repl_root), rc);
+        }
     }
 
     slapi_ch_free ((void**)&dn);
@@ -3240,14 +3431,18 @@ replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv)
 	ReplicaId supplier_id = 0;
 	char *supplier_purl = NULL;
 
-	if ( ruv_get_first_id_and_purl(supplier_ruv, &supplier_id, &supplier_purl) == RUV_SUCCESS )
+	if ( ruv_get_first_id_and_purl(supplier_ruv, &supplier_id, &supplier_purl) == RUV_SUCCESS)
 	{
 		RUV *local_ruv = NULL;
 
 		PR_Lock(r->repl_lock);
 
 		local_ruv =  (RUV*)object_get_data (r->repl_ruv);
-		PR_ASSERT (local_ruv);
+
+		if(is_cleaned_rid(supplier_id) || local_ruv == NULL){
+			PR_Unlock(r->repl_lock);
+			return;
+		}
 
 		if ( ruv_local_contains_supplier(local_ruv, supplier_id) == 0 )
 		{
@@ -3579,3 +3774,67 @@ replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value )
 
 	return rc;
 }
+
+void
+replica_add_cleanruv_data(Replica *r, char *val)
+{
+    int i;
+
+    PR_Lock(r->repl_lock);
+
+    for (i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] != NULL; i++); /* goto the end of the list */
+    r->repl_cleanruv_data[i] = slapi_ch_strdup(val); /* append to list */
+    r->repl_cleanruv_data[i + 1] = NULL;
+
+    PR_Unlock(r->repl_lock);
+}
+
+void
+replica_remove_cleanruv_data(Replica *r, char *val)
+{
+    int i;
+
+    PR_Lock(r->repl_lock);
+
+    for(i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i] && strcmp(r->repl_cleanruv_data[i], val) != 0; i++);
+    if( i < CLEANRIDSIZ ){
+        slapi_ch_free_string(&r->repl_cleanruv_data[i]);
+        for(; i < CLEANRIDSIZ; i++){
+            /* rewrite entire array */
+            r->repl_cleanruv_data[i] = r->repl_cleanruv_data[i + 1];
+        }
+    }
+
+    PR_Unlock(r->repl_lock);
+}
+
+CSN *
+replica_get_cleanruv_maxcsn(Replica *r, ReplicaId rid)
+{
+    CSN *newcsn;
+    char *csnstr;
+    char *token;
+    char *iter;
+    int repl_rid = 0;
+    int i;
+
+    PR_Lock(r->repl_lock);
+
+    for(i = 0; i < CLEANRIDSIZ && r->repl_cleanruv_data[i]; i++){
+        token = ldap_utf8strtok_r(r->repl_cleanruv_data[i], ":", &iter);
+        if(token){
+            repl_rid = atoi(token);
+        }
+        csnstr = ldap_utf8strtok_r(iter, ":", &iter);
+        if(repl_rid == rid){
+            newcsn = csn_new();
+            csn_init_by_string(newcsn, csnstr);
+            PR_Unlock(r->repl_lock);
+            return newcsn;
+        }
+    }
+
+    PR_Unlock(r->repl_lock);
+
+    return NULL;
+}
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 771af61..89651cf 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -2,15 +2,15 @@
  * This Program is free software; you can redistribute it and/or modify it under
  * the terms of the GNU General Public License as published by the Free Software
  * Foundation; version 2 of the License.
- * 
+ *
  * This Program is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place, Suite 330, Boston, MA 02111-1307 USA.
- * 
+ *
  * In addition, as a special exception, Red Hat, Inc. gives You the additional
  * right to link the code of this Program with code not covered under the GNU
  * General Public License ("Non-GPL Code") and to distribute linked combinations
@@ -28,9 +28,9 @@
  * version of the file, but you are not obligated to do so. If you do not wish to
  * provide this exception without modification, you must delete this exception
  * statement from your version and license this file solely under the GPL without
- * exception. 
- * 
- * 
+ * exception.
+ *
+ *
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
  * All rights reserved.
@@ -58,13 +58,17 @@
 #define CLEANRUVLEN         8
 #define CLEANALLRUV         "CLEANALLRUV"
 #define CLEANALLRUVLEN      11
-#define RELEASERUV          "RELEASERUV"
-#define RELEASERUVLEN       10
 #define REPLICA_RDN         "cn=replica"
+#define CLEANALLRUV_ID      "CleanAllRUV Task"
+#define ABORT_CLEANALLRUV_ID    "Abort CleanAllRUV Task"
 
 int slapi_log_urp = SLAPI_LOG_REPL;
-static ReplicaId cleaned_rid = 0;
-static int released_rid = 0;
+static ReplicaId cleaned_rids[CLEANRIDSIZ + 1] = {0};
+static ReplicaId aborted_rids[CLEANRIDSIZ + 1] = {0};
+static Slapi_RWLock *rid_lock = NULL;
+static Slapi_RWLock *abort_rid_lock = NULL;
+static PRLock *notify_lock = NULL;
+static PRCondVar *notify_cvar = NULL;
 
 /* Forward Declartions */
 static int replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
@@ -72,7 +76,7 @@ static int replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry*
 static int replica_config_post_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 static int replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 static int replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
-
+static int replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,  int *returncode, char *returntext, void *arg);
 static int replica_config_change_type_and_id (Replica *r, const char *new_type, const char *new_id, char *returntext, int apply_mods);
 static int replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext, int apply_mods);
 static int replica_config_change_flags (Replica *r, const char *new_flags,  char *returntext, int apply_mods);
@@ -80,9 +84,18 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
 static int replica_execute_cl2ldif_task (Object *r, char *returntext);
 static int replica_execute_ldif2cl_task (Object *r, char *returntext);
 static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
-static int replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, char *returntext);
-static int replica_execute_release_ruv_task(Object *r, ReplicaId rid);
-static struct berval *create_ruv_payload(char *value);
+static int replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext);
+static void replica_cleanallruv_thread(void *arg);
+static void replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task);
+static int check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task);
+static int check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task);
+static int replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result);
+static int replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct berval *payload);
+static int replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task);
+static int replica_cleanallruv_replica_alive(Repl_Agmt *agmt);
+static int replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task);
+static int get_cleanruv_task_count();
+static int get_abort_cleanruv_task_count();
 static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
 static int replica_task_done(Replica *replica);
 static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
@@ -105,29 +118,59 @@ int
 replica_config_init()
 {
 	s_configLock = PR_NewLock ();
+
 	if (s_configLock == NULL)
 	{
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
-                        "failed to cretate configuration lock; NSPR error - %d\n",
+                        "failed to create configuration lock; NSPR error - %d\n",
                         PR_GetError ());
 		return -1;
 	}
+	rid_lock = slapi_new_rwlock();
+	if(rid_lock == NULL)
+	{
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
+				"failed to create rid_lock; NSPR error - %d\n", PR_GetError ());
+		return -1;
+	}
+	abort_rid_lock = slapi_new_rwlock();
+	if(abort_rid_lock == NULL)
+	{
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
+				"failed to create abort_rid_lock; NSPR error - %d\n", PR_GetError ());
+		return -1;
+	}
+	if ( ( notify_lock = PR_NewLock()) == NULL ) {
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
+				"failed to create notify lock; NSPR error - %d\n", PR_GetError ());
+		return -1;
+	}
+	if ( ( notify_cvar = PR_NewCondVar( notify_lock )) == NULL ) {
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
+				"failed to create notify cond var; NSPR error - %d\n", PR_GetError ());
+		return -1;
+	}
 
 	/* config DSE must be initialized before we get here */
 	slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
-								   CONFIG_FILTER, replica_config_add, NULL); 
+								   CONFIG_FILTER, replica_config_add, NULL);
     slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
 								   CONFIG_FILTER, replica_config_modify,NULL);
     slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
 								   CONFIG_FILTER, dont_allow_that, NULL);
     slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
-								   CONFIG_FILTER, replica_config_delete,NULL); 
+								   CONFIG_FILTER, replica_config_delete,NULL);
     slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
-								   CONFIG_FILTER, replica_config_search,NULL); 
-    slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, 
+								   CONFIG_FILTER, replica_config_search,NULL);
+    slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP,
                                    CONFIG_BASE, LDAP_SCOPE_SUBTREE,
                                    CONFIG_FILTER, replica_config_post_modify,
                                    NULL);
+
+    /* register the CLEANALLRUV & ABORT task */
+    slapi_task_register_handler("cleanallruv", replica_cleanall_ruv_task);
+    slapi_task_register_handler("abort cleanallruv", replica_cleanall_ruv_abort);
+
     return 0;
 }
 
@@ -142,7 +185,7 @@ replica_config_destroy ()
 
 	/* config DSE must be initialized before we get here */
 	slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
-								 CONFIG_FILTER, replica_config_add); 
+								 CONFIG_FILTER, replica_config_add);
     slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
 								 CONFIG_FILTER, replica_config_modify);
     slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
@@ -151,26 +194,26 @@ replica_config_destroy ()
 								 CONFIG_FILTER, replica_config_delete);
     slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
 								 CONFIG_FILTER, replica_config_search);
-    slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, 
+    slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
                                  CONFIG_BASE, LDAP_SCOPE_SUBTREE,
                                  CONFIG_FILTER, replica_config_post_modify);
 }
 
-static int 
-replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, 
+static int
+replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
 					   int *returncode, char *errorbuf, void *arg)
 {
 	Replica *r = NULL;
-    multimaster_mtnode_extension *mtnode_ext;	
+    multimaster_mtnode_extension *mtnode_ext;
     char *replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
 	char buf [SLAPI_DSE_RETURNTEXT_SIZE];
 	char *errortext = errorbuf ? errorbuf : buf;
-    
+
 	if (errorbuf)
 	{
 		errorbuf[0] = '\0';
-	} 
- 
+	}
+
 	*returncode = LDAP_SUCCESS;
 
 	PR_Lock (s_configLock);
@@ -185,16 +228,16 @@ replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
     {
         PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica already configured for %s", replica_root);
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: %s\n", errortext);
-        *returncode = LDAP_UNWILLING_TO_PERFORM;    
-        goto done;   
+        *returncode = LDAP_UNWILLING_TO_PERFORM;
+        goto done;
     }
 
     /* create replica object */
     r = replica_new_from_entry (e, errortext, PR_TRUE /* is a newly added entry */);
     if (r == NULL)
     {
-        *returncode = LDAP_OPERATIONS_ERROR;    
-        goto done;   
+        *returncode = LDAP_OPERATIONS_ERROR;
+        goto done;
     }
 
 	/* Set the mapping tree node state, and the referrals from the RUV */
@@ -220,24 +263,24 @@ done:
 
 	if (*returncode != LDAP_SUCCESS)
 	{
-        if (mtnode_ext->replica) 
+        if (mtnode_ext->replica)
             object_release (mtnode_ext->replica);
 		return SLAPI_DSE_CALLBACK_ERROR;
 	}
-	else	
+	else
 		return SLAPI_DSE_CALLBACK_OK;
 }
 
-static int 
-replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, 
+static int
+replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
 					   int *returncode, char *returntext, void *arg)
 {
     int rc= 0;
    	LDAPMod **mods;
 	int i, apply_mods;
-    multimaster_mtnode_extension *mtnode_ext;	
+    multimaster_mtnode_extension *mtnode_ext;
 	Replica *r = NULL;
-    char *replica_root = NULL; 
+    char *replica_root = NULL;
 	char buf [SLAPI_DSE_RETURNTEXT_SIZE];
 	char *errortext = returntext ? returntext : buf;
     char *config_attr, *config_attr_value;
@@ -252,7 +295,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 
     /* just let internal operations originated from replication plugin to go through */
     slapi_pblock_get (pb, SLAPI_OPERATION, &op);
-    slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);                
+    slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
 
     if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
         (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
@@ -264,7 +307,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
     replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
 
 	PR_Lock (s_configLock);
-    
+
     mtnode_ext = _replica_config_get_mtnode_ext (e);
     PR_ASSERT (mtnode_ext);
 
@@ -276,7 +319,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
         PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica does not exist for %s", replica_root);
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
                         errortext);
-        *returncode = LDAP_OPERATIONS_ERROR;    
+        *returncode = LDAP_OPERATIONS_ERROR;
         goto done;
     }
 
@@ -287,7 +330,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
     for (apply_mods = 0; apply_mods <= 1; apply_mods++)
 	{
 		/* we only allow the replica ID and type to be modified together e.g.
-		   if converting a read only replica to a master or vice versa - 
+		   if converting a read only replica to a master or vice versa -
 		   we will need to change both the replica ID and the type at the same
 		   time - we must disallow changing the replica ID if the type is not
 		   being changed and vice versa
@@ -304,7 +347,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
                 break;
 
             config_attr = (char *) mods[i]->mod_type;
-            PR_ASSERT (config_attr); 
+            PR_ASSERT (config_attr);
 
             /* disallow modifications or removal of replica root,
                replica name and replica state attributes */
@@ -313,14 +356,14 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
                 strcasecmp (config_attr, attr_state) == 0)
             {
                 *returncode = LDAP_UNWILLING_TO_PERFORM;
-                PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "modification of %s attribute is not allowed", 
-                         config_attr);                         
-                slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", 
+                PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "modification of %s attribute is not allowed",
+                         config_attr);
+                slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
                                 errortext);
             }
             /* this is a request to delete an attribute */
-            else if (mods[i]->mod_op & LDAP_MOD_DELETE || mods[i]->mod_bvalues == NULL
-                     || mods[i]->mod_bvalues[0]->bv_val == NULL) 
+            else if ((mods[i]->mod_op & LDAP_MOD_DELETE) || mods[i]->mod_bvalues == NULL
+                     || mods[i]->mod_bvalues[0]->bv_val == NULL)
             {
                 /* currently, you can only remove referral,
 				   legacy consumer or bind dn attribute */
@@ -345,10 +388,9 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
                 else
                 {
                     *returncode = LDAP_UNWILLING_TO_PERFORM;
-                    PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "deletion of %s attribute is not allowed", config_attr);                         
-                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", 
-                                    errortext);
-                }                
+                    PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "deletion of %s attribute is not allowed", config_attr);
+                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", errortext);
+                }
             }
             else    /* modify an attribute */
             {
@@ -356,8 +398,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 
                 if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
 			    {
-				    *returncode = replica_config_change_updatedn (r, mods[i],
-												       errortext, apply_mods);
+				    *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
                 }
                 else if (strcasecmp (config_attr, attr_replicaType) == 0)
 			    {
@@ -367,16 +408,14 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 			    {
 					new_repl_id = slapi_ch_strdup(config_attr_value);
                 }
-                else if (strcasecmp (config_attr, attr_flags) == 0) 
+                else if (strcasecmp (config_attr, attr_flags) == 0)
                 {
-                    *returncode = replica_config_change_flags (r, config_attr_value,
-													           errortext, apply_mods);	
+                    *returncode = replica_config_change_flags (r, config_attr_value, errortext, apply_mods);
                 }
-                else if (strcasecmp (config_attr, TASK_ATTR) == 0) 
+                else if (strcasecmp (config_attr, TASK_ATTR) == 0)
                 {
-                    *returncode = replica_execute_task (mtnode_ext->replica, config_attr_value,
-													    errortext, apply_mods);
-                } 
+                    *returncode = replica_execute_task (mtnode_ext->replica, config_attr_value, errortext, apply_mods);
+                }
                 else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
                 {
                     if (apply_mods)
@@ -391,14 +430,14 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 						if (!replica_is_legacy_consumer (r)) {
 							consumer5_set_mapping_tree_state_for_replica(r, NULL);
 						}
-                    }                    
+                    }
                 }
 				else if (strcasecmp (config_attr, type_replicaPurgeDelay) == 0)
 				{
-					if (apply_mods && config_attr_value && config_attr_value[0]) 
+					if (apply_mods && config_attr_value && config_attr_value[0])
 					{
 						PRUint32 delay;
-						if (isdigit (config_attr_value[0])) 
+						if (isdigit (config_attr_value[0]))
 						{
 							delay = (unsigned int)atoi(config_attr_value);
 							replica_set_purge_delay(r, delay);
@@ -409,7 +448,7 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 				}
 				else if (strcasecmp (config_attr, type_replicaTombstonePurgeInterval) == 0)
 				{
-					if (apply_mods && config_attr_value && config_attr_value[0]) 
+					if (apply_mods && config_attr_value && config_attr_value[0])
 					{
 						long interval;
 						interval = atol (config_attr_value);
@@ -439,17 +478,14 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
                     *returncode = LDAP_UNWILLING_TO_PERFORM;
                     PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
 								 "modification of attribute %s is not allowed in replica entry", config_attr);
-                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", 
-                                    errortext);
-                } 
+                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", errortext);
+                }
             }
 		}
 
 		if (new_repl_id || new_repl_type)
 		{
-			*returncode = replica_config_change_type_and_id(r, new_repl_type,
-															new_repl_id, errortext,
-															apply_mods);
+			*returncode = replica_config_change_type_and_id(r, new_repl_type, new_repl_id, errortext, apply_mods);
 			slapi_ch_free_string(&new_repl_id);
 			slapi_ch_free_string(&new_repl_type);
 		}
@@ -458,9 +494,9 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 done:
     if (mtnode_ext->replica)
         object_release (mtnode_ext->replica);
-	
+
 	/* slapi_ch_free accepts NULL pointer */
-	slapi_ch_free ((void**)&replica_root);
+	slapi_ch_free_string(&replica_root);
 
 	PR_Unlock (s_configLock);
 
@@ -474,9 +510,9 @@ done:
     }
 }
 
-static int 
+static int
 replica_config_post_modify(Slapi_PBlock *pb,
-                           Slapi_Entry* entryBefore, 
+                           Slapi_Entry* entryBefore,
                            Slapi_Entry* e,
                            int *returncode,
                            char *returntext,
@@ -485,9 +521,9 @@ replica_config_post_modify(Slapi_PBlock *pb,
     int rc= 0;
     LDAPMod **mods;
     int i, apply_mods;
-    multimaster_mtnode_extension *mtnode_ext;    
+    multimaster_mtnode_extension *mtnode_ext;
     Replica *r = NULL;
-    char *replica_root = NULL; 
+    char *replica_root = NULL;
     char buf [SLAPI_DSE_RETURNTEXT_SIZE];
     char *errortext = returntext ? returntext : buf;
     char *config_attr, *config_attr_value;
@@ -503,7 +539,7 @@ replica_config_post_modify(Slapi_PBlock *pb,
 
     /* just let internal operations originated from replication plugin to go through */
     slapi_pblock_get (pb, SLAPI_OPERATION, &op);
-    slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);                
+    slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
 
     if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
         (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
@@ -515,7 +551,7 @@ replica_config_post_modify(Slapi_PBlock *pb,
     replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
 
     PR_Lock (s_configLock);
-    
+
     mtnode_ext = _replica_config_get_mtnode_ext (e);
     PR_ASSERT (mtnode_ext);
 
@@ -529,7 +565,7 @@ replica_config_post_modify(Slapi_PBlock *pb,
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "replica_config_post_modify: %s\n",
                         errortext);
-        *returncode = LDAP_OPERATIONS_ERROR;    
+        *returncode = LDAP_OPERATIONS_ERROR;
         goto done;
     }
 
@@ -540,7 +576,7 @@ replica_config_post_modify(Slapi_PBlock *pb,
     for (apply_mods = 0; apply_mods <= 1; apply_mods++)
     {
         /* we only allow the replica ID and type to be modified together e.g.
-           if converting a read only replica to a master or vice versa - 
+           if converting a read only replica to a master or vice versa -
            we will need to change both the replica ID and the type at the same
            time - we must disallow changing the replica ID if the type is not
            being changed and vice versa
@@ -554,7 +590,7 @@ replica_config_post_modify(Slapi_PBlock *pb,
                 break;
 
             config_attr = (char *) mods[i]->mod_type;
-            PR_ASSERT (config_attr); 
+            PR_ASSERT (config_attr);
 
             /* disallow modifications or removal of replica root,
                replica name and replica state attributes */
@@ -564,16 +600,16 @@ replica_config_post_modify(Slapi_PBlock *pb,
             {
                 *returncode = LDAP_UNWILLING_TO_PERFORM;
                 PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
-                             "modification of %s attribute is not allowed", 
-                             config_attr);                         
+                             "modification of %s attribute is not allowed",
+                             config_attr);
                 slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-                                "replica_config_post_modify: %s\n", 
+                                "replica_config_post_modify: %s\n",
                                 errortext);
             }
             /* this is a request to delete an attribute */
-            else if (mods[i]->mod_op & LDAP_MOD_DELETE || 
+            else if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
                      mods[i]->mod_bvalues == NULL ||
-                     mods[i]->mod_bvalues[0]->bv_val == NULL) 
+                     mods[i]->mod_bvalues[0]->bv_val == NULL)
             {
                 ;
             }
@@ -581,7 +617,7 @@ replica_config_post_modify(Slapi_PBlock *pb,
             {
                 config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
 
-                if (strcasecmp (config_attr, TASK_ATTR) == 0) 
+                if (strcasecmp (config_attr, TASK_ATTR) == 0)
                 {
                     flag_need_cleanup = 1;
                 }
@@ -605,7 +641,7 @@ done:
 
     if (mtnode_ext->replica)
         object_release (mtnode_ext->replica);
-    
+
     if (*returncode != LDAP_SUCCESS)
     {
         return SLAPI_DSE_CALLBACK_ERROR;
@@ -616,8 +652,8 @@ done:
     }
 }
 
-static int 
-replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, 
+static int
+replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
 					   int *returncode, char *returntext, void *arg)
 {
     multimaster_mtnode_extension *mtnode_ext;
@@ -650,26 +686,26 @@ replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter
 	return SLAPI_DSE_CALLBACK_OK;
 }
 
-static int 
-replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, 
+static int
+replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode,
                        char *returntext, void *arg)
 {
-    multimaster_mtnode_extension *mtnode_ext;   
+    multimaster_mtnode_extension *mtnode_ext;
     int changeCount = 0;
 	PRBool reapActive = PR_FALSE;
     char val [64];
 
 	/* add attribute that contains number of entries in the changelog for this replica */
-	
+
     PR_Lock (s_configLock);
-    
+
 	mtnode_ext = _replica_config_get_mtnode_ext (e);
 	PR_ASSERT (mtnode_ext);
-    
+
 	if (mtnode_ext->replica) {
 		Replica *replica;
 		object_acquire (mtnode_ext->replica);
-		if (cl5GetState () == CL5_STATE_OPEN) {    
+		if (cl5GetState () == CL5_STATE_OPEN) {
 			changeCount = cl5GetOperationCount (mtnode_ext->replica);
 		}
 		replica = (Replica*)object_get_data (mtnode_ext->replica);
@@ -688,9 +724,9 @@ replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter
     return SLAPI_DSE_CALLBACK_OK;
 }
 
-static int 
+static int
 replica_config_change_type_and_id (Replica *r, const char *new_type,
-								   const char *new_id, char *returntext, 
+								   const char *new_id, char *returntext,
 								   int apply_mods)
 {
     int type;
@@ -770,8 +806,8 @@ replica_config_change_type_and_id (Replica *r, const char *new_type,
     return LDAP_SUCCESS;
 }
 
-static int 
-replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext, 
+static int
+replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext,
                                 int apply_mods)
 {
     PR_ASSERT (r);
@@ -790,7 +826,7 @@ replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext
     return LDAP_SUCCESS;
 }
 
-static int replica_config_change_flags (Replica *r, const char *new_flags,  
+static int replica_config_change_flags (Replica *r, const char *new_flags,
                                         char *returntext, int apply_mods)
 {
     PR_ASSERT (r);
@@ -807,10 +843,10 @@ static int replica_config_change_flags (Replica *r, const char *new_flags,
     return LDAP_SUCCESS;
 }
 
-static int replica_execute_task (Object *r, const char *task_name, char *returntext, 
+static int replica_execute_task (Object *r, const char *task_name, char *returntext,
                                  int apply_mods)
 {
-   
+
     if (strcasecmp (task_name, CL2LDIF_TASK) == 0)
     {
 		if (apply_mods)
@@ -848,13 +884,14 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
 	{
 		int temprid = atoi(&(task_name[CLEANALLRUVLEN]));
 		if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
-			PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)", temprid, task_name);
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_execute_task: %s\n", returntext);
-			return LDAP_OPERATIONS_ERROR;
+				PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)", temprid, task_name);
+				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_execute_task: %s\n", returntext);
+				return LDAP_OPERATIONS_ERROR;
 		}
 		if (apply_mods)
 		{
-			return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, returntext);
+			Slapi_Task *empty_task = NULL;
+			return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext);
 		}
 		else
 			return LDAP_SUCCESS;
@@ -862,22 +899,22 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
 	else
 	{
         PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "unsupported replica task - %s", task_name);
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
-                        "replica_execute_task: %s\n", returntext);        
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                        "replica_execute_task: %s\n", returntext);
         return LDAP_OPERATIONS_ERROR;
     }
-    
+
 }
 
-static int 
-replica_cleanup_task (Object *r, const char *task_name, char *returntext, 
+static int
+replica_cleanup_task (Object *r, const char *task_name, char *returntext,
                       int apply_mods)
 {
     int rc = LDAP_SUCCESS;
     if (apply_mods) {
         Replica *replica = (Replica*)object_get_data (r);
         if (NULL == replica) {
-            rc = LDAP_OPERATIONS_ERROR;    
+            rc = LDAP_OPERATIONS_ERROR;
         } else {
             rc = replica_task_done(replica);
         }
@@ -913,19 +950,19 @@ replica_task_done(Replica *replica)
     mod.mod_type = (char *)TASK_ATTR;
     mod.mod_bvalues = NULL;
 
-    slapi_modify_internal_set_pb_ext(pb, replica_sdn, mods, NULL/* controls */, 
-                      NULL/* uniqueid */, 
+    slapi_modify_internal_set_pb_ext(pb, replica_sdn, mods, NULL/* controls */,
+                      NULL/* uniqueid */,
                       repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
                       0/* flags */);
     slapi_modify_internal_pb (pb);
 
     slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
     if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_ATTRIBUTE)) {
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "replica_task_done: "
                         "failed to remove (%s) attribute from (%s) entry; "
                         "LDAP error - %d\n",
-                        TASK_ATTR, replica_dn, rc);   
+                        TASK_ATTR, replica_dn, rc);
     }
 
     slapi_pblock_destroy (pb);
@@ -945,9 +982,9 @@ static int replica_execute_cl2ldif_task (Object *r, char *returntext)
     if (cl5GetState () != CL5_STATE_OPEN)
     {
         PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
-                        "replica_execute_cl2ldif_task: %s\n", returntext);        
-        rc = LDAP_OPERATIONS_ERROR;    
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                        "replica_execute_cl2ldif_task: %s\n", returntext);
+        rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
 
@@ -958,25 +995,25 @@ static int replica_execute_cl2ldif_task (Object *r, char *returntext)
        <replica name>.ldif */
     clDir = cl5GetDir ();
     if (NULL == clDir) {
-        rc = LDAP_OPERATIONS_ERROR;    
+        rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
 
     replica = (Replica*)object_get_data (r);
     if (NULL == replica) {
-        rc = LDAP_OPERATIONS_ERROR;    
+        rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
 
     PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
     slapi_ch_free_string (&clDir);
 
-    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                     "Beginning changelog export of replica \"%s\"\n",
                     replica_get_name(replica));
     rc = cl5ExportLDIF (fName, rlist);
     if (rc == CL5_SUCCESS) {
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "Finished changelog export of replica \"%s\"\n",
                         replica_get_name(replica));
         rc = LDAP_SUCCESS;
@@ -984,9 +1021,9 @@ static int replica_execute_cl2ldif_task (Object *r, char *returntext)
         PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
                      "Failed changelog export replica %s; "
                      "changelog error - %d", replica_get_name(replica), rc);
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "replica_execute_cl2ldif_task: %s\n", returntext);
-        rc = LDAP_OPERATIONS_ERROR;    
+        rc = LDAP_OPERATIONS_ERROR;
     }
 bail:
     return rc;
@@ -1004,8 +1041,8 @@ static int replica_execute_ldif2cl_task (Object *r, char *returntext)
     if (cl5GetState () != CL5_STATE_OPEN)
     {
         PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
-                        "replica_execute_ldif2cl_task: %s\n", returntext);        
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                        "replica_execute_ldif2cl_task: %s\n", returntext);
         rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
@@ -1017,13 +1054,13 @@ static int replica_execute_ldif2cl_task (Object *r, char *returntext)
        <replica name>.ldif */
     clDir = cl5GetDir ();
     if (NULL == clDir) {
-        rc = LDAP_OPERATIONS_ERROR;    
+        rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
 
     replica = (Replica*)object_get_data (r);
     if (NULL == replica) {
-        rc = LDAP_OPERATIONS_ERROR;    
+        rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
 
@@ -1035,19 +1072,19 @@ static int replica_execute_ldif2cl_task (Object *r, char *returntext)
         PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
                      "failed to close changelog to import changelog data; "
                      "changelog error - %d", rc);
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "replica_execute_ldif2cl_task: %s\n", returntext);
         rc = LDAP_OPERATIONS_ERROR;
         goto bail;
     }
-    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                     "Beginning changelog import of replica \"%s\"\n",
                     replica_get_name(replica));
     imprc = cl5ImportLDIF (clDir, fName, rlist);
     slapi_ch_free_string (&clDir);
     if (CL5_SUCCESS == imprc)
     {
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "Finished changelog import of replica \"%s\"\n",
                         replica_get_name(replica));
     }
@@ -1056,7 +1093,7 @@ static int replica_execute_ldif2cl_task (Object *r, char *returntext)
         PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
                      "Failed changelog import replica %s; "
                      "changelog error - %d", replica_get_name(replica), rc);
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                         "replica_execute_ldif2cl_task: %s\n", returntext);
         imprc = LDAP_OPERATIONS_ERROR;
     }
@@ -1069,10 +1106,10 @@ static int replica_execute_ldif2cl_task (Object *r, char *returntext)
     }
     else
     {
-        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
             "replica_execute_ldif2cl_task: failed to start changelog at %s\n",
             config.dir?config.dir:"null config dir");
-        rc = LDAP_OPERATIONS_ERROR;    
+        rc = LDAP_OPERATIONS_ERROR;
     }
 bail:
     changelog5_config_done(&config);
@@ -1080,7 +1117,7 @@ bail:
     return imprc?imprc:rc;
 }
 
-static multimaster_mtnode_extension * 
+static multimaster_mtnode_extension *
 _replica_config_get_mtnode_ext (const Slapi_Entry *e)
 {
     const char *replica_root;
@@ -1095,7 +1132,7 @@ _replica_config_get_mtnode_ext (const Slapi_Entry *e)
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
                         "configuration entry %s missing %s attribute\n",
                         slapi_entry_get_dn((Slapi_Entry *)e),
-                        attr_replicaRoot);   
+                        attr_replicaRoot);
         return NULL;
     }
 
@@ -1107,14 +1144,14 @@ _replica_config_get_mtnode_ext (const Slapi_Entry *e)
     {
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
                         "failed to locate mapping tree node for dn %s\n",
-                        slapi_sdn_get_dn(sdn));        
+                        slapi_sdn_get_dn(sdn));
     }
     else
     {
         /* check if replica object already exists for the specified subtree */
-        ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);    
+        ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
     }
-    
+
     slapi_sdn_free (&sdn);
 
     return ext;
@@ -1123,26 +1160,24 @@ _replica_config_get_mtnode_ext (const Slapi_Entry *e)
 int
 replica_execute_cleanruv_task_ext(Object *r, ReplicaId rid)
 {
-	slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_extop: calling clean_ruv_ext\n");
-	return replica_execute_cleanruv_task(r, rid, NULL);
+    return replica_execute_cleanruv_task(r, rid, NULL);
 }
 
 static int
 replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not used */)
 {
-	int rc = 0;
 	Object *RUVObj;
 	RUV *local_ruv = NULL;
 	Replica *replica = (Replica*)object_get_data (r);
-
+	int rc = 0;
 	PR_ASSERT (replica);
 
 	slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_task: cleaning rid (%d)...\n",(int)rid);
 	RUVObj = replica_get_ruv(replica);
 	PR_ASSERT(RUVObj);
 	local_ruv =  (RUV*)object_get_data (RUVObj);
-	/* Need to check that : 
-	 *  - rid is not the local one 
+	/* Need to check that :
+	 *  - rid is not the local one
 	 *  - rid is not the last one
 	 */
 	if ((replica_get_rid(replica) == rid) ||
@@ -1156,12 +1191,11 @@ replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not
 
 	/* Update Mapping Tree to reflect RUV changes */
 	consumer5_set_mapping_tree_state_for_replica(replica, NULL);
-	
+
 	/*
-	 *  Clean the changelog RUV's, and set the rids
+	 *  Clean the changelog RUV's
 	 */
 	cl5CleanRUV(rid);
-	delete_released_rid();
 
 	if (rc != RUV_SUCCESS){
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_task: task failed(%d)\n",rc);
@@ -1171,506 +1205,1566 @@ replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not
 	return LDAP_SUCCESS;
 }
 
-static int
-replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, char *returntext)
+const char *
+fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val)
 {
-	PRThread *thread = NULL;
-	Repl_Connection *conn;
-	Replica *replica;
-	Object *agmt_obj;
-	Repl_Agmt *agmt;
-	ConnResult crc;
-	cleanruv_data *data = NULL;
-	const Slapi_DN *dn = NULL;
-	struct berval *payload = NULL;
-	char *ridstr = NULL;
-	int send_msgid = 0;
-	int agmt_count = 0;
-	int rc = 0;
+    Slapi_Attr *attr;
+    Slapi_Value *val = NULL;
 
-	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: cleaning rid (%d)...\n",(int)rid);
+    if (slapi_entry_attr_find(e, attrname, &attr) != 0)
+        return default_val;
 
-	/*
-	 *  Grab the replica
-	 */
-	if(r){
-		replica = (Replica*)object_get_data (r);
-	} else {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is NULL, aborting task\n");
-		return -1;
-	}
-	/*
-	 *  Create payload
-	 */
-	ridstr = slapi_ch_smprintf("%d:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)));
-	payload = create_ruv_payload(ridstr);
-	if(payload == NULL){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to create ext op payload, aborting task\n");
-		slapi_ch_free_string(&ridstr);
-		return -1;
-	}
+    slapi_attr_first_value(attr, &val);
+    return slapi_value_get_string(val);
+}
 
+static int
+replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+		                      int *returncode, char *returntext, void *arg)
+{
+    Slapi_Task *task = NULL;
+    const Slapi_DN *task_dn;
+    Slapi_DN *dn = NULL;
+    Object *r;
+    const char *base_dn;
+    const char *rid_str;
+    ReplicaId rid;
+    int rc = SLAPI_DSE_CALLBACK_OK;
+
+    /* allocate new task now */
+    task = slapi_new_task(slapi_entry_get_ndn(e));
+    if(task == NULL){
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Failed to create new task\n");
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
 
-	set_cleaned_rid(rid);
+    /*
+     *  Get our task settings
+     */
+    if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
+        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    if ((rid_str = fetch_attr(e, "replica-id", 0)) == NULL){
+        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
 
-	agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
-	while (agmt_obj)
-	{
-		agmt = (Repl_Agmt*)object_get_data (agmt_obj);
-		if(!agmt_is_enabled(agmt)){
-			agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-			continue;
-		}
-		dn = agmt_get_dn_byref(agmt);
-		conn = (Repl_Connection *)agmt_get_connection(agmt);
-		if(conn == NULL){
-			/* no connection for this agreement, and move on */
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: the replica (%s), is "
-				"missing the connection.  This replica will not be cleaned.\n", slapi_sdn_get_dn(dn));
-			agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-			continue;
-		}
-		crc = conn_connect(conn);
-		if (CONN_OPERATION_FAILED == crc ){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to connect "
-				"to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
-		} else if (CONN_SSL_NOT_ENABLED == crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to acquire "
-				"repl agmt connection (%s), errror %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
-		} else {
-			conn_cancel_linger(conn);
-			crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, payload, NULL, &send_msgid);
-			if (CONN_OPERATION_SUCCESS != crc){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to send "
-					"cleanruv extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
-			} else {
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: successfully sent "
-					"cleanruv extended op to (%s)\n",slapi_sdn_get_dn(dn));
-				agmt_count++;
-			}
-			conn_start_linger(conn);
-		}
-		if(crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica (%s) has not "
-				"been cleaned.  You will need to rerun the CLEANALLRUV task on this replica.\n", slapi_sdn_get_dn(dn));
-			rc = crc;
-		}
-		agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-	}
+    task_dn = slapi_entry_get_sdn(e);
+    /*
+     *  Check the rid
+     */
+    rid = atoi(rid_str);
+    if (rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)",
+            rid, slapi_sdn_get_dn(task_dn));
+        cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
+        rc = LDAP_OPERATIONS_ERROR;
+        goto out;
+    }
+    /*
+     *  Get the replica object
+     */
+    dn = slapi_sdn_new_dn_byval(base_dn);
+    if((r = replica_get_replica_from_dn(dn)) == NULL){
+        *returncode = LDAP_OPERATIONS_ERROR ;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
 
-	/*
-	 *  We're done with the payload, free it.
-	 */
-	if(payload){
-		ber_bvfree(payload);
-	}
-	slapi_ch_free_string(&ridstr);
+    /* clean the RUV's */
+    rc = replica_execute_cleanall_ruv_task (r, rid, task, returntext);
 
-	/*
-	 *  Now run the cleanruv task
-	 */
-	replica_execute_cleanruv_task (r, rid, returntext);
-
-	if(rc == 0 && agmt_count > 0){  /* success, but we need to check our replicas */
-		/*
-		 *  Launch the cleanruv monitoring thread.  Once all the replicas are cleaned it will release the rid
-		 */
-		data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
-		if (data == NULL) {
-			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to allocate "
-				"cleanruv_data.  Aborting task.\n");
-			return -1;
-		}
-		data->repl_obj = r;
-		data->rid = rid;
-
-		thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_monitor_thread,
-				(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
-				PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
-		if (thread == NULL) {
-			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: unable to create cleanAllRUV "
-				"monitoring thread.  Aborting task.\n");
-		}
-	} else if(rc == 0){ /* success */
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Successfully Finished.\n");
-	} else {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Task failed (%d)\n",rc);
-	}
+out:
+    if(rc){
+        cleanruv_log(task, CLEANALLRUV_ID, "Task failed...(%d)", rc);
+        *returncode = rc;
+        slapi_task_finish(task, *returncode);
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+    } else {
+        rc = SLAPI_DSE_CALLBACK_OK;
+    }
+    slapi_sdn_free(&dn);
 
-	return rc;
+    return rc;
 }
 
 /*
- *  After all the cleanAllRUV extended ops have been sent, we need to monitoring those replicas'
- *  RUVs.  Once the rid is cleaned, then we need to release it, and push this "release"
- *  to the other replicas
+ *  CLEANALLRUV task
+ *
+ *  [1]  Get the maxcsn from the RUV of the rid we want to clean
+ *  [2]  Create the payload for the "cleanallruv" extended ops
+ *  [3]  Create "monitor" thread to do the real work.
+ *
  */
-void
-replica_cleanallruv_monitor_thread(void *arg)
+static int
+replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext)
 {
-	Object *agmt_obj;
-	LDAP *ld;
-	Repl_Connection *conn;
-	Repl_Agmt *agmt;
-	Replica *replica;;
-	cleanruv_data *data = arg;
-	LDAPMessage *result, *entry;
-	BerElement   *ber;
-	time_t start_time;
-	struct berval **vals;
-	char *rid_text;
-	char *attrs[2];
-	char *attr;
-	int replicas_cleaned = 0;
-	int found = 0;
-	int crc;
-	int rc = 0;
-	int i;
+    PRThread *thread = NULL;
+    Slapi_Task *pre_task = NULL; /* this is supposed to be null for logging */
+    Replica *replica;
+    Object *ruv_obj;
+    cleanruv_data *data = NULL;
+    CSN *maxcsn = NULL;
+    const RUV *ruv;
+    struct berval *payload = NULL;
+    char *ridstr = NULL;
+    char csnstr[CSN_STRSIZE];
+    int rc = 0;
+
+    if(get_cleanruv_task_count() >= CLEANRIDSIZ){
+        /* we are already running the maximum number of tasks */
+        cleanruv_log(pre_task, CLEANALLRUV_ID,
+    	    "Exceeded maximum number of active CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
+        returntext = PR_smprintf("Exceeded maximum number of active CLEANALLRUV tasks(%d), "
+            "you must wait for one to finish.", CLEANRIDSIZ);
+        return LDAP_UNWILLING_TO_PERFORM;
+    }
 
-	/*
-	 *  Initialize our settings
-	 */
-	attrs[0] = "nsds50ruv";
-	attrs[1] = NULL;
-	rid_text = slapi_ch_smprintf("{replica %d ldap", data->rid);
-	replica = (Replica*)object_get_data (data->repl_obj);
-	start_time = current_time();
+    /*
+     *  Grab the replica
+     */
+    if(r){
+        replica = (Replica*)object_get_data (r);
+    } else {
+    	cleanruv_log(pre_task, CLEANALLRUV_ID, "Replica is NULL, aborting task");
+        rc = -1;
+        goto fail;
+    }
+    /*
+     *  Check if this is a consumer
+     */
+    if(replica_get_type(replica) == REPLICA_TYPE_READONLY){
+        /* this is a consumer, send error */
+        cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to clean rid (%d), task can not be run on a consumer",rid);
+        if(task){
+            rc = -1;
+            slapi_task_finish(task, rc);
+        }
+        return -1;
+    }
+    /*
+     *  Grab the max csn of the deleted replica
+     */
+    ruv_obj = replica_get_ruv(replica);
+    ruv = object_get_data (ruv_obj);
+    if(ruv_get_rid_max_csn(ruv, &maxcsn, rid) == RUV_BAD_DATA){
+        /* no maxcsn, can not proceed */
+        cleanruv_log(pre_task, CLEANALLRUV_ID, "Could not find maxcsn for rid (%d)", rid);
+        rc = -1;
+        object_release(ruv_obj);
+        goto fail;
+    } else {
+        object_release(ruv_obj);
+        if(maxcsn == NULL || csn_get_replicaid(maxcsn) == 0){
+            /*
+             *  This is for consistency with extop csn creation, where
+             *  we want the csn string to be "0000000000000000000" not ""
+             */
+            csn_free(&maxcsn);
+            maxcsn = csn_new();
+            csn_init_by_string(maxcsn, "");
+        }
+        csn_as_string(maxcsn, PR_FALSE, csnstr);
+    }
+    /*
+     *  Create payload
+     */
+    ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)), csnstr);
+    payload = create_ruv_payload(ridstr);
+    slapi_ch_free_string(&ridstr);
+
+    if(payload == NULL){
+        cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to create extended op payload, aborting task");
+        rc = -1;
+        goto fail;
+    }
 
-	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Waiting for all the replicas to get cleaned...\n");
+    /*
+     *  Launch the cleanallruv thread.  Once all the replicas are cleaned it will release the rid
+     */
+    data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
+    if (data == NULL) {
+        cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to allocate cleanruv_data.  Aborting task.");
+        rc = -1;
+        goto fail;
+    }
+    data->repl_obj = r;
+    data->replica = replica;
+    data->rid = rid;
+    data->task = task;
+    data->maxcsn = maxcsn;
+    data->payload = payload;
+    data->sdn = NULL;
+
+    thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread,
+        (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+        PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+    if (thread == NULL) {
+        rc = -1;
+        goto fail;
+    } else {
+        goto done;
+    }
 
-	while(!slapi_is_shutting_down())
-	{
-		DS_Sleep(PR_SecondsToInterval(10));
-		found = 0;
-		agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
-		while (agmt_obj){
-			agmt = (Repl_Agmt*)object_get_data (agmt_obj);
-			if(!agmt_is_enabled(agmt)){
-				agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-				continue;
-			}
-			/*
-			 *  Get the replication connection
-			 */
-			conn = (Repl_Connection *)agmt_get_connection(agmt);
-			crc = conn_connect(conn);
-			if (CONN_OPERATION_FAILED == crc ){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: monitor thread failed to connect "
-					"to repl agreement connection (%s), error %d\n","", ACQUIRE_TRANSIENT_ERROR);
-				continue;
-			} else if (CONN_SSL_NOT_ENABLED == crc){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: monitor thread failed to acquire "
-					"repl agmt connection (%s), error %d\n","", ACQUIRE_FATAL_ERROR);
-				continue;
-			}
-			/*
-			 *  Get the LDAP connection handle from the conn
-			 */
-			ld = conn_get_ldap(conn);
-			if(ld == NULL){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: monitor thread failed to get LDAP "
-					"handle from the replication agmt (%s).  Moving on to the next agmt.\n",agmt_get_long_name(agmt));
-				continue;
-			}
-			/*
-			 *  Search this replica for its tombstone/ruv entry
-			 */
-			conn_cancel_linger(conn);
-			conn_lock(conn);
-			rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(agmt_get_replarea(agmt)), LDAP_SCOPE_SUBTREE,
-				"(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
-				attrs, 0, NULL, NULL, NULL, 0, &result);
-			if(rc != LDAP_SUCCESS){
-				/*
-				 *  Couldn't contact ldap server, what should we do?
-				 *
-				 *  Skip it and move on!  It's the admin's job to make sure all the replicas are up and running
-				 */
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: monitor thread failed to contact "
-					"agmt (%s), moving on to the next agmt.\n", agmt_get_long_name(agmt));
-				conn_unlock(conn);
-				conn_start_linger(conn);
-				continue;
-			}
-			/*
-			 *  There is only one entry.  Check its "nsds50ruv" for our cleaned rid
-			 */
-			entry = ldap_first_entry( ld, result );
-			if ( entry != NULL ) {
-				for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
-					/* make sure the attribute is nsds50ruv */
-					if(strcasecmp(attr,"nsds50ruv") != 0){
-						continue;
-					}
-					if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
-						for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
-							/* look for this replica */
-							if(strstr(rid_text, vals[i]->bv_val)){
-								/* rid has not been cleaned yet, start over */
-								found = 1;
-								break;
-							}
-						}
-						ldap_value_free_len(vals);
-					}
-					ldap_memfree( attr );
-				}
-				if ( ber != NULL ) {
-					ber_free( ber, 0 );
-				}
-			}
-			ldap_msgfree( result );
-			/*
-			 *  Unlock the connection, and start the linger timer
-			 */
-			conn_unlock(conn);
-			conn_start_linger(conn);
-
-			if(found){
-				/*
-				 *  If we've been trying to clean these replicas for over an hour, just quit
-				 */
-				if( (current_time() - start_time) > 3600){
-					slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: timed out checking if replicas have "
-						"been cleaned.  The rid has not been released, you need to rerun the task.\n");
-					goto done;
-				}
-				/*
-				 *  a rid has not been cleaned yet, go back to sleep and check them again
-				 */
-				break;
-			}
+fail:
+    cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to clean rid (%d)",rid);
+    if(task){
+        slapi_task_finish(task, rc);
+    }
+    if(payload){
+        ber_bvfree(payload);
+    }
+    csn_free(&maxcsn);
+    object_release (r);
 
-			agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-		}
-		if(!found){
-			/*
-			 *  The replicas have been cleaned!  Next, release the rid
-			 */
-			replicas_cleaned = 1;
-			break;
-		}
-	} /* while */
+done:
 
-	/*
-	 *  If the replicas are cleaned, release the rid
-	 */
-	if(replicas_cleaned){
-		rc = replica_execute_release_ruv_task(data->repl_obj, data->rid);
-		if(rc == 0){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Successfully Finished.  All active "
-				"replicas have been cleaned.\n");
-		} else {
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Failed: Replica ID was not released (%d)  "
-			"You will need to rerun the task.\n", rc);
-		}
-	} else {
-		/*
-		 *  Shutdown
-		 */
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: slapd shutting down, you will need to rerun the task.\n");
-	}
+    return rc;
+}
 
-done:
-	slapi_ch_free((void **)&rid_text);
-	slapi_ch_free((void **)&data);
+void
+replica_cleanallruv_thread_ext(void *arg)
+{
+    replica_cleanallruv_thread(arg);
 }
 
 /*
- *  This function releases the cleaned rid so that it can be reused.
- *  We send this operation to all the known active replicas.
+ *  CLEANALLRUV Thread
+ *
+ *  [1]  Wait for the maxcsn to be covered
+ *  [2]  Make sure all the replicas are alive
+ *  [3]  Set the cleaned rid
+ *  [4]  Send the cleanAllRUV extop to all the replicas
+ *  [5]  Manually send the CLEANRUV task to replicas that do not support CLEANALLRUV
+ *  [6]  Wait for all the replicas to be cleaned.
+ *  [7]  Trigger cl trimming, release the rid, and remove all the "cleanallruv" attributes
+ *       from the config.
  */
-static int
-replica_execute_release_ruv_task(Object *r, ReplicaId rid)
+static void
+replica_cleanallruv_thread(void *arg)
 {
-	Repl_Connection *conn;
-	Replica *replica = (Replica*)object_get_data (r);
-	Object *agmt_obj;
-	Repl_Agmt *agmt;
-	ConnResult crc;
-	const Slapi_DN *dn = NULL;
-	struct berval *payload = NULL;
-	char *ridstr = NULL;
-	int send_msgid = 0;
-	int rc = 0;
+    Object *ruv_obj = NULL;
+    Object *agmt_obj = NULL;
+    Repl_Agmt *agmt = NULL;
+    RUV *ruv = NULL;
+    cleanruv_data *data = arg;
+    char csnstr[CSN_STRSIZE];
+    char *returntext = NULL;
+    char *rid_text = NULL;
+    int found_dirty_rid = 1;
+    int agmt_not_notified = 1;
+    int interval = 10;
+    int free_obj = 0;
+    int rc = 0;
+
+    /*
+     *  Initialize our settings
+     */
+    if(data->replica == NULL && data->repl_obj == NULL){
+        /*
+         * This thread was initiated at startup because the process did not finish.  Due
+         * to timing issues, we need to wait to grab the replica obj until we get here.
+         */
+        data->repl_obj = replica_get_replica_from_dn(data->sdn);
+        data->replica = (Replica*)object_get_data(data->repl_obj);
+        free_obj = 1;
+    }
+    if(data->replica == NULL && data->repl_obj){
+        data->replica = (Replica*)object_get_data(data->repl_obj);
+    }
+    if( data->replica && data->repl_obj == NULL){
+        data->repl_obj = object_new(data->replica, NULL);
+        free_obj = 1;
+    }
+    if(data->task){
+        slapi_task_begin(data->task, 1);
+    }
+    rid_text = slapi_ch_smprintf("{replica %d ldap", data->rid);
+    csn_as_string(data->maxcsn, PR_FALSE, csnstr);
+
+    /*
+     *  Add the cleanallruv task to the repl config - so we can handle restarts
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID, "Cleaning rid (%d)...", data->rid);
+    add_cleaned_rid(data->rid, data->replica, csnstr); /* marks config that we started cleaning a rid */
+    /*
+     *  First, wait for the maxcsn to be covered
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID, "Waiting to process all the updates from the deleted replica...");
+    ruv_obj = replica_get_ruv(data->replica);
+    ruv = object_get_data (ruv_obj);
+    while(data->maxcsn && !is_task_aborted(data->rid) && !is_cleaned_rid(data->rid) && !slapi_is_shutting_down()){
+        if(csn_get_replicaid(data->maxcsn) == 0 || ruv_covers_csn(ruv,data->maxcsn)){
+            /* We are caught up, now we can clean the ruv's */
+            break;
+        }
+        DS_Sleep(PR_SecondsToInterval(5));
+    }
+    object_release(ruv_obj);
+    /*
+     *  Next, make sure all the replicas are up and running before sending off the clean ruv tasks
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to be online...");
+    if(check_agmts_are_alive(data->replica, data->rid, data->task)){
+        /* error, aborted or shutdown */
+        goto done;
+    }
+    /*
+     *  Make sure all the replicas have seen the max csn
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to receive all the deleted replica updates...");
+    if(check_agmts_are_caught_up(data->replica, data->rid, csnstr, data->task)){
+        /* error, aborted or shutdown */
+        goto done;
+    }
+    /*
+     *  Set the rid as notified - this blocks the changelog from sending out updates
+     *  during this process, as well as prevents the db ruv from getting polluted.
+     */
+    set_cleaned_rid(data->rid);
+    /*
+     *  Now send the cleanruv extended op to all the agreements
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID, "Sending cleanAllRUV task to all the replicas...");
+    while(agmt_not_notified && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
+        agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
+        if(agmt_obj == NULL){
+            /* no agmts, just clean this replica */
+            break;
+        }
+        while (agmt_obj){
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+            if(!agmt_is_enabled(agmt)){ /* skip disabled replicas */
+                agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+                continue;
+            }
+            if(replica_cleanallruv_send_extop(agmt, data->rid, data->task, data->payload, 1) == 0){
+                agmt_not_notified = 0;
+            } else {
+                agmt_not_notified = 1;
+                break;
+            }
+            agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+        }
 
-	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: releasing rid (%d)...\n", rid);
+        if(is_task_aborted(data->rid)){
+            goto done;
+        }
+        if(agmt_not_notified == 0){
+           break;
+        }
+        /*
+         *  need to sleep between passes
+         */
+        cleanruv_log(data->task, CLEANALLRUV_ID, "Not all replicas have received the "
+            "cleanallruv extended op, retrying in %d seconds",interval);
+        PR_Lock( notify_lock );
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+        PR_Unlock( notify_lock );
+
+        if(interval < 14400){ /* 4 hour max */
+            interval = interval * 2;
+        } else {
+            interval = 14400;
+        }
+    }
+    /*
+     *  Run the CLEANRUV task
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID,"Cleaning local ruv's...");
+    replica_execute_cleanruv_task (data->repl_obj, data->rid, returntext);
+    /*
+     *  Wait for all the replicas to be cleaned
+     */
+    cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to be cleaned...");
+
+    interval = 10;
+    while(found_dirty_rid && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
+        agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
+        if(agmt_obj == NULL){
+            break;
+        }
+        while (agmt_obj && !slapi_is_shutting_down()){
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+            if(!agmt_is_enabled(agmt)){ /* skip disabled replicas */
+                agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+                continue;
+            }
+            if(replica_cleanallruv_check_ruv(agmt, rid_text, data->task) == 0){
+                found_dirty_rid = 0;
+            } else {
+                found_dirty_rid = 1;
+                break;
+            }
+            agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+        }
+        /* If the task is abort or everyone is cleaned, break out */
+        if(is_task_aborted(data->rid)){
+            goto done;
+        }
+        if(found_dirty_rid == 0){
+           break;
+        }
+        /*
+         *  need to sleep between passes
+         */
+        cleanruv_log(data->task, CLEANALLRUV_ID, "Replicas have not been cleaned yet, "
+            "retrying in %d seconds", interval);
+        PR_Lock( notify_lock );
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+        PR_Unlock( notify_lock );
+
+        if(interval < 14400){ /* 4 hour max */
+            interval = interval * 2;
+        } else {
+            interval = 14400;
+        }
+    } /* while */
 
-	/*
-	 * Set the released rid, and trigger cl trimmming
-	 */
-	set_released_rid((int)rid);
-	trigger_cl_trimming();
-	/*
-	 *  Create payload
-	 */
-	ridstr = slapi_ch_smprintf("%d:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)));
-	payload = create_ruv_payload(ridstr);
-	if(payload == NULL){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_task: failed to create ext op payload, aborting op\n");
-		rc = -1;
-		goto done;
-	}
+done:
+    /*
+     *  If the replicas are cleaned, release the rid, and trim the changelog
+     */
+    if(!found_dirty_rid){
+        trigger_cl_trimming(data->rid);
+        delete_cleaned_rid(data->replica, data->rid, data->maxcsn);
+        cleanruv_log(data->task, CLEANALLRUV_ID, "Successfully cleaned rid(%d).", data->rid);
+        slapi_task_finish(data->task, rc);
+    } else {
+        /*
+         *  Shutdown or abort
+         */
+        if(!is_task_aborted(data->rid)){
+            cleanruv_log(data->task, CLEANALLRUV_ID,"Server shutting down.  Process will resume at server startup");
+        } else {
+            cleanruv_log(data->task, CLEANALLRUV_ID,"Task aborted for rid(%d).",data->rid);
+        }
+        if(data->task){
+            slapi_task_finish(data->task, rc);
+        }
+    }
 
-	agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
-	while (agmt_obj)
-	{
-		agmt = (Repl_Agmt*)object_get_data (agmt_obj);
-		if(!agmt_is_enabled(agmt)){
-			agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-			continue;
-		}
-		dn = agmt_get_dn_byref(agmt);
-		conn = (Repl_Connection *)agmt_get_connection(agmt);
-		if(conn == NULL){
-			/* no connection for this agreement, log error, and move on */
-			agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-			continue;
-		}
-		crc = conn_connect(conn);
-		if (CONN_OPERATION_FAILED == crc ){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_task: failed to connect "
-				"to repl agmt (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
-			rc = LDAP_OPERATIONS_ERROR;
-		} else if (CONN_SSL_NOT_ENABLED == crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_task: failed to acquire "
-				"repl agmt (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
-			rc = LDAP_OPERATIONS_ERROR;
-		} else {
-			conn_cancel_linger(conn);
-			crc = conn_send_extended_operation(conn, REPL_RELEASERUV_OID, payload, NULL, &send_msgid);
-			if (CONN_OPERATION_SUCCESS != crc){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to send "
-					"releaseRUV extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
-				rc = LDAP_OPERATIONS_ERROR;
-			} else {
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: successfully sent "
-					"releaseRUV extended op to (%s)\n",slapi_sdn_get_dn(dn));
-			}
-			conn_start_linger(conn);
-		}
-		if(crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica (%s) has not "
-					"been released.  You will need to rerun the task\n",
-					slapi_sdn_get_dn(dn));
-			rc = crc;
-		}
-		agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
-	}
+    if(data->payload){
+        ber_bvfree(data->payload);
+    }
+    if(data->repl_obj && free_obj){
+        object_release(data->repl_obj);
+    }
+    slapi_sdn_free(&data->sdn);
+    slapi_ch_free_string(&rid_text);
+    csn_free(&data->maxcsn);
+    slapi_ch_free((void **)&data);
+}
 
-done:
-	/*
-	 *  reset the released/clean rid
-	 */
-	if(rc == 0){
-		set_released_rid(ALREADY_RELEASED);
-		delete_cleaned_rid();
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Successfully released rid (%d)\n", rid);
-	} else {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Failed to release rid (%d), error (%d)\n", rid, rc);
-	}
+/*
+ *  Waits for all the repl agmts to be have have the maxcsn.  Returns error only on abort or shutdown
+ */
+static int
+check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task)
+{
+    Object *agmt_obj;
+    Repl_Agmt *agmt;
+    char *rid_text;
+    int not_all_caughtup = 1;
+    int interval = 10;
+
+    rid_text = slapi_ch_smprintf("{replica %d ldap", rid);
+
+    while(not_all_caughtup && !is_task_aborted(rid) && !slapi_is_shutting_down()){
+        agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
+        if(agmt_obj == NULL){
+            not_all_caughtup = 0;
+            break;
+        }
+        while (agmt_obj){
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+            if(!agmt_is_enabled(agmt)){ /* skip disabled replicas */
+                agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+                continue;
+            }
+            if(replica_cleanallruv_check_maxcsn(agmt, rid_text, maxcsn, task) == 0){
+                not_all_caughtup = 0;
+            } else {
+                not_all_caughtup = 1;
+                break;
+            }
+            agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+        } /* agmt while */
 
-	if(payload)
-		ber_bvfree(payload);
+        if(not_all_caughtup == 0 || is_task_aborted(rid) ){
+            break;
+        }
+        cleanruv_log(task, CLEANALLRUV_ID, "Not all replicas caught up, retrying in %d seconds",interval);
+        PR_Lock( notify_lock );
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+        PR_Unlock( notify_lock );
+
+        if(interval < 14400){ /* 4 hour max */
+            interval = interval * 2;
+        } else {
+            interval = 14400;
+        }
+    }
+    slapi_ch_free_string(&rid_text);
 
-	slapi_ch_free_string(&ridstr);
+    if(is_task_aborted(rid)){
+        return -1;
+    }
 
-	return rc;
+    return not_all_caughtup;
 }
 
-static struct berval *
-create_ruv_payload(char *value){
-	struct berval *req_data = NULL;
-	BerElement *tmp_bere = NULL;
+/*
+ *  Waits for all the repl agmts to be online.  Returns error only on abort or shutdown
+ */
+static int
+check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
+{
+    Object *agmt_obj;
+    Repl_Agmt *agmt;
+    int not_all_alive = 1;
+    int interval = 10;
+
+    while(not_all_alive && is_task_aborted(rid) == 0 && !slapi_is_shutting_down()){
+        agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
+        if(agmt_obj == NULL){
+            not_all_alive = 0;
+            break;
+        }
+        while (agmt_obj){
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+            if(!agmt_is_enabled(agmt)){ /* skip disabled replicas */
+                agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+                continue;
+            }
+            if(replica_cleanallruv_replica_alive(agmt) == 0){
+                not_all_alive = 0;
+            } else {
+                not_all_alive = 1;
+                break;
+            }
+            agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
+        }
 
-	if ((tmp_bere = der_alloc()) == NULL){
-		goto error;
-	}
-	if (ber_printf(tmp_bere, "{s", value) == -1){
-		goto error;
-	}
+        if(not_all_alive == 0 || is_task_aborted(rid)){
+            break;
+        }
+        cleanruv_log(task, CLEANALLRUV_ID, "Not all replicas online, retrying in %d seconds...",interval);
+        PR_Lock( notify_lock );
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+        PR_Unlock( notify_lock );
 
-	if (ber_printf(tmp_bere, "}") == -1){
-		goto error;
-	}
+        if(interval < 14400){ /* 4 hour max */
+            interval = interval * 2;
+        } else {
+            interval = 14400;
+        }
+    }
+    if(is_task_aborted(rid)){
+        return -1;
+    }
 
-	if (ber_flatten(tmp_bere, &req_data) == -1){
-		goto error;
-	}
+    return not_all_alive;
+}
 
-	goto done;
+/*
+ *  Create the CLEANALLRUV extended op payload
+ */
+struct berval *
+create_ruv_payload(char *value)
+{
+    struct berval *req_data = NULL;
+    BerElement *tmp_bere = NULL;
+
+    if ((tmp_bere = der_alloc()) == NULL){
+        goto error;
+    }
+    if (ber_printf(tmp_bere, "{s", value) == -1){
+        goto error;
+    }
+    if (ber_printf(tmp_bere, "}") == -1){
+        goto error;
+    }
+    if (ber_flatten(tmp_bere, &req_data) == -1){
+        goto error;
+    }
+    goto done;
 
 error:
-	if (NULL != req_data){
-		ber_bvfree(req_data);
-		req_data = NULL;
-	}
+    if (NULL != req_data){
+        ber_bvfree(req_data);
+        req_data = NULL;
+    }
 
 done:
-	if (NULL != tmp_bere){
-		ber_free(tmp_bere, 1);
-		tmp_bere = NULL;
-	}
+    if (NULL != tmp_bere){
+        ber_free(tmp_bere, 1);
+        tmp_bere = NULL;
+    }
+
+    return req_data;
+}
+
+/*
+ *  Manually add the CLEANRUV task to replicas that do not support
+ *  the CLEANALLRUV task.
+ */
+static void
+replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
+{
+    Repl_Connection *conn;
+    ConnResult crc = 0;
+    LDAP *ld;
+    Slapi_DN *dn;
+    struct berval *vals[2];
+    struct berval val;
+    LDAPMod *mods[2];
+    LDAPMod mod;
+    char *repl_dn = NULL;
+    char data[15];
+    int rc;
 
-	return req_data;
+    if((conn = conn_new(agmt)) == NULL){
+        return;
+    }
+    crc = conn_connect(conn);
+    if (CONN_OPERATION_SUCCESS != crc){
+        conn_delete_internal_ext(conn);
+        return;
+    }
+    ld = conn_get_ldap(conn);
+    if(ld == NULL){
+        conn_delete_internal_ext(conn);
+        return;
+    }
+    val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", rid);
+    dn = agmt_get_replarea(agmt);
+    mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
+    mod.mod_type = "nsds5task";
+    mod.mod_bvalues = vals;
+    vals [0] = &val;
+    vals [1] = NULL;
+    val.bv_val = data;
+    mods[0] = &mod;
+    mods[1] = NULL;
+    repl_dn = PR_smprintf("cn=replica,cn=\"%s\",cn=mapping tree,cn=config", slapi_sdn_get_dn(dn));
+    /*
+     *  Add task to remote replica
+     */
+    rc = ldap_modify_ext_s( ld, repl_dn, mods, NULL, NULL);
+
+    if(rc != LDAP_SUCCESS){
+    	cleanruv_log(task, CLEANALLRUV_ID, "Failed to add CLEANRUV task replica "
+            "(%s).  You will need to manually run the CLEANRUV task on this replica (%s) error (%d)",
+            agmt_get_long_name(agmt), agmt_get_hostname(agmt), rc);
+    }
+    slapi_ch_free_string(&repl_dn);
+    conn_delete_internal_ext(conn);
 }
 
+/*
+ *  Check if the rid is in our list of "cleaned" rids
+ */
 int
 is_cleaned_rid(ReplicaId rid)
 {
-	if(rid == cleaned_rid){
-		return 1;
-	} else {
-		return 0;
-	}
+    int i;
+
+    slapi_rwlock_rdlock(rid_lock);
+    for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != 0; i++){
+        if(rid == cleaned_rids[i]){
+            slapi_rwlock_unlock(rid_lock);
+            return 1;
+        }
+    }
+    slapi_rwlock_unlock(rid_lock);
+
+    return 0;
 }
 
+int
+is_task_aborted(ReplicaId rid)
+{
+	int i;
+
+    if(rid == 0){
+        return 0;
+    }
+    slapi_rwlock_rdlock(abort_rid_lock);
+    for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != 0; i++){
+        if(rid == aborted_rids[i]){
+            slapi_rwlock_unlock(abort_rid_lock);
+            return 1;
+        }
+    }
+    slapi_rwlock_unlock(abort_rid_lock);
+    return 0;
+}
+
+/*
+ *  Just add the rid to the in memory, as we don't want it to survive after a restart,
+ *  This prevent the changelog from sending updates from this rid, and the local ruv
+ *  will not be updated either.
+ */
 void
-set_cleaned_rid( ReplicaId rid )
+set_cleaned_rid(ReplicaId rid)
 {
-	cleaned_rid = rid;
+    int i;
+
+    slapi_rwlock_wrlock(rid_lock);
+    for(i = 0; i < CLEANRIDSIZ; i++){
+        if(cleaned_rids[i] == 0){
+            cleaned_rids[i] = rid;
+            cleaned_rids[i + 1] = 0;
+        }
+    }
+    slapi_rwlock_unlock(rid_lock);
 }
 
+/*
+ *  Add the rid and maxcsn to the repl config (so we can resume after a server restart)
+ */
 void
-delete_cleaned_rid()
+add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
 {
-	cleaned_rid = 0;
+    Slapi_PBlock *pb;
+    struct berval *vals[2];
+    struct berval val;
+    LDAPMod *mods[2];
+    LDAPMod mod;
+    char data[CSN_STRSIZE + 10];
+    char *dn;
+    int rc;
+
+    /*
+     *  Write the rid & maxcsn to the config entry
+     */
+    val.bv_len = PR_snprintf(data, sizeof(data),"%d:%s", rid, maxcsn);
+    dn = replica_get_dn(r);
+    pb = slapi_pblock_new();
+    mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
+    mod.mod_type = (char *)type_replicaCleanRUV;
+    mod.mod_bvalues = vals;
+    vals [0] = &val;
+    vals [1] = NULL;
+    val.bv_val = data;
+    mods[0] = &mod;
+    mods[1] = NULL;
+
+    replica_add_cleanruv_data(r, val.bv_val);
+
+    slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
+        repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+    slapi_modify_internal_pb (pb);
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if (rc != LDAP_SUCCESS){
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to update replica "
+            "config (%d), rid (%d)\n", rc, rid);
+    }
+    slapi_ch_free_string(&dn);
+    slapi_pblock_destroy(pb);
 }
 
-int
-get_released_rid()
+/*
+ *  Add aborted rid and repl root to config in case of a server restart
+ */
+void
+add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
 {
-	return released_rid;
+    Slapi_PBlock *pb;
+    struct berval *vals[2];
+    struct berval val;
+    LDAPMod *mods[2];
+    LDAPMod mod;
+    char *data;
+    char *dn;
+    int rc;
+    int i;
+
+    slapi_rwlock_wrlock(abort_rid_lock);
+    for(i = 0; i < CLEANRIDSIZ; i++){
+        if(aborted_rids[i] == 0){
+            aborted_rids[i] = rid;
+            aborted_rids[i + 1] = 0;
+            break;
+        }
+    }
+    slapi_rwlock_unlock(abort_rid_lock);
+    /*
+     *  Write the rid to the config entry
+     */
+    dn = replica_get_dn(r);
+    pb = slapi_pblock_new();
+    data = PR_smprintf("%d:%s", rid, repl_root);
+    mod.mod_op  = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
+    mod.mod_type = (char *)type_replicaAbortCleanRUV;
+    mod.mod_bvalues = vals;
+    vals [0] = &val;
+    vals [1] = NULL;
+    val.bv_val = data;
+    val.bv_len = strlen (data);
+    mods[0] = &mod;
+    mods[1] = NULL;
+
+    slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
+        repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+    slapi_modify_internal_pb (pb);
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if (rc != LDAP_SUCCESS){
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to update "
+        "replica config (%d), rid (%d)\n", rc, rid);
+    }
+
+    slapi_ch_free_string(&dn);
+    slapi_ch_free_string(&data);
+    slapi_pblock_destroy(pb);
 }
 
-int
-is_released_rid(int rid)
+void
+delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
+    Slapi_PBlock *pb;
+    LDAPMod *mods[2];
+    LDAPMod mod;
+    struct berval *vals[2];
+    struct berval val;
+    char *data;
+    char *dn;
+    int rc;
+    int i;
+
+    if(r == NULL)
+        return;
+
+    /*
+     *  Remove this rid, and optimize the array
+     */
+    slapi_rwlock_wrlock(abort_rid_lock);
+    for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != rid; i++); /* found rid, stop */
+    for(; i < CLEANRIDSIZ; i++){
+        /* rewrite entire array */
+        aborted_rids[i] = aborted_rids[i + 1];
+    }
+    slapi_rwlock_unlock(abort_rid_lock);
+    /*
+     *  Prepare the mods for the config entry
+     */
+    dn = replica_get_dn(r);
+    pb = slapi_pblock_new();
+    data = PR_smprintf("%d:%s", (int)rid, repl_root);
+
+    mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
+    mod.mod_type = (char *)type_replicaAbortCleanRUV;
+    mod.mod_bvalues = vals;
+    vals [0] = &val;
+    vals [1] = NULL;
+    val.bv_val = data;
+    val.bv_len = strlen (data);
+    mods[0] = &mod;
+    mods[1] = NULL;
+
+    slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+    slapi_modify_internal_pb (pb);
+    slapi_pblock_destroy (pb);
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if (rc != LDAP_SUCCESS){
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
+            "config (%d), rid (%d)\n", rc, rid);
+    }
+
+    slapi_ch_free_string(&dn);
+    slapi_ch_free_string(&data);
+}
+
+/*
+ *  Remove the rid from our list, and the config
+ */
+void
+delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn)
 {
-	if(rid == released_rid){
-		return 1;
-	} else {
-		return 0;
-	}
+    Slapi_PBlock *pb;
+    Object *agmt_obj;
+    Repl_Agmt *agmt;
+    LDAPMod *mods[2];
+    LDAPMod mod;
+    struct berval *vals[2];
+    struct berval val;
+    char *dn;
+    char data[CSN_STRSIZE + 10];
+    char csnstr[CSN_STRSIZE];
+    int rc;
+    int i;
+
+    if(r == NULL || maxcsn == NULL)
+        return;
+
+    /*
+     *  Remove this rid, and optimize the array
+     */
+    slapi_rwlock_wrlock(rid_lock);
+    for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != rid; i++); /* found rid, stop */
+    for(; i < CLEANRIDSIZ; i++){
+        /* rewrite entire array */
+        cleaned_rids[i] = cleaned_rids[i + 1];
+    }
+    slapi_rwlock_unlock(rid_lock);
+    /*
+     *  Prepare the mods for the config entry
+     */
+    csn_as_string(maxcsn, PR_FALSE, csnstr);
+    val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s", (int)rid, csnstr);
+    dn = replica_get_dn(r);
+    pb = slapi_pblock_new();
+    mod.mod_op  = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
+    mod.mod_type = (char *)type_replicaCleanRUV;
+    mod.mod_bvalues = vals;
+    vals [0] = &val;
+    vals [1] = NULL;
+    val.bv_val = data;
+    mods[0] = &mod;
+    mods[1] = NULL;
+
+    replica_remove_cleanruv_data(r, data);
+
+    slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+    slapi_modify_internal_pb (pb);
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if (rc != LDAP_SUCCESS){
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to remove replica config "
+            "(%d), rid (%d)\n", rc, rid);
+    }
+    slapi_pblock_destroy (pb);
+    slapi_ch_free_string(&dn);
+    /*
+     *  Now release the cleaned rid from the repl agmts
+     */
+    agmt_obj = agmtlist_get_first_agreement_for_replica (r);
+    while (agmt_obj){
+        agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+        if(!agmt_is_enabled(agmt)){
+            agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
+            continue;
+        }
+        agmt_set_cleanruv_data(agmt, rid, CLEANRUV_RELEASED);
+        agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
+    }
 }
 
+/*
+ *  Abort the CLEANALLRUV task
+ */
 int
-is_already_released_rid()
+replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+        int *returncode, char *returntext, void *arg)
 {
-	if(released_rid == ALREADY_RELEASED){
-		return 1;
-	} else {
-		return 0;
-	}
+    PRThread *thread = NULL;
+    struct berval *payload = NULL;
+    Slapi_Task *task = NULL;
+    Replica *replica;
+    ReplicaId rid;
+    cleanruv_data *data = NULL;
+    const Slapi_DN *dn;
+    Object *r;
+    CSN *maxcsn;
+    const char *base_dn;
+    const char *rid_str;
+    char *ridstr;
+    int rc = SLAPI_DSE_CALLBACK_OK;
+
+    if(get_abort_cleanruv_task_count() >= CLEANRIDSIZ){
+        /* we are already running the maximum number of tasks */
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,
+    	    "Exceeded maximum number of active ABORT CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
+        returntext = PR_smprintf("Exceeded maximum number of active ABORT CLEANALLRUV tasks(%d), "
+            "you must wait for one to finish.", CLEANRIDSIZ);
+        *returncode = LDAP_OPERATIONS_ERROR;
+        return SLAPI_DSE_CALLBACK_ERROR;
+    }
+
+    /* allocate new task now */
+    task = slapi_new_task(slapi_entry_get_ndn(e));
+    /*
+     *  Get our task settings
+     */
+    if ((rid_str = fetch_attr(e, "replica-id", 0)) == NULL){
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Missing required attr \"replica-id\"");
+        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Missing required attr \"replica-base-dn\"");
+        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    /*
+     *  Check the rid
+     */
+    rid = atoi(rid_str);
+    if (rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
+        PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)",
+            rid, slapi_sdn_get_dn(slapi_entry_get_sdn(e)));
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,"%s", returntext);
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    /*
+     *  Get the replica object
+     */
+    dn = slapi_sdn_new_dn_byval(base_dn);
+    if((r = replica_get_replica_from_dn(dn)) == NULL){
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Failed to find replica from dn(%s)", base_dn);
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    /*
+     *  Create payload
+     */
+    ridstr = slapi_ch_smprintf("%d:%s", rid, base_dn);
+    payload = create_ruv_payload(ridstr);
+
+    if(payload == NULL){
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to create extended op payload, aborting task");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    /*
+     *  Stop the cleaning, and delete the rid
+     */
+    replica = (Replica*)object_get_data (r);
+    maxcsn = replica_get_cleanruv_maxcsn(replica, rid);
+    delete_cleaned_rid(replica, rid, maxcsn);
+    add_aborted_rid(rid, replica, (char *)base_dn);
+    stop_ruv_cleaning();
+    /*
+     *  Prepare the abort struct and fire off the thread
+     */
+    data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
+    if (data == NULL) {
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Failed to allocate abort_cleanruv_data.  Aborting task.");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+        goto out;
+    }
+    data->repl_obj = r; /* released in replica_abort_task_thread() */
+    data->replica = replica;
+    data->task = task;
+    data->payload = payload;
+    data->rid = rid;
+    data->repl_root = slapi_ch_strdup(base_dn);
+    data->sdn = NULL;
+
+    thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
+                (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+                PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+    if (thread == NULL) {
+        object_release(r);
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Unable to create abort thread.  Aborting task.");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rc = SLAPI_DSE_CALLBACK_ERROR;
+    }
+
+out:
+
+    csn_free(&maxcsn);
+    slapi_ch_free_string(&ridstr);
+
+    if(rc != SLAPI_DSE_CALLBACK_OK){
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Abort Task failed (%d)", rc);
+        slapi_task_finish(task, rc);
+    }
+
+    return rc;
+}
+
+/*
+ *  Abort CLEANALLRUV task thread
+ */
+void
+replica_abort_task_thread(void *arg)
+{
+    cleanruv_data *data = (cleanruv_data *)arg;
+    Repl_Agmt *agmt;
+    Object *agmt_obj;
+    int agmt_not_notified = 1;
+    int interval = 10;
+    int release_it = 0;
+
+    /*
+     *   Need to build the replica from the dn
+     */
+    if(data->replica == NULL && data->repl_obj == NULL){
+        /*
+         * This thread was initiated at startup because the process did not finish.  Due
+         * to timing issues, we need to wait to grab the replica obj until we get here.
+         */
+        if((data->repl_obj = replica_get_replica_from_dn(data->sdn)) == NULL){
+            cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Failed to get replica from dn (%s).", slapi_sdn_get_dn(data->sdn));
+            goto done;
+        }
+        if(data->replica == NULL && data->repl_obj){
+            data->replica = (Replica*)object_get_data(data->repl_obj);
+        }
+        release_it = 1;
+    }
+
+    /*
+     *  Now send the cleanruv extended op to all the agreements
+     */
+    while(agmt_not_notified && !slapi_is_shutting_down()){
+        agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
+        while (agmt_obj){
+            agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+            if(!agmt_is_enabled(agmt)){ /* skip disabled replicas */
+                agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+                continue;
+            }
+            if(replica_cleanallruv_send_abort_extop(agmt, data->task, data->payload)){
+                agmt_not_notified = 1;
+                break;
+            } else {
+                /* success */
+                agmt_not_notified = 0;
+            }
+            agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
+        } /* while loop for agmts */
+
+        if(agmt_not_notified == 0){
+            /* everybody has been contacted */
+            break;
+        }
+        /*
+         *  need to sleep between passes
+         */
+        cleanruv_log(data->task, ABORT_CLEANALLRUV_ID,"Retrying in %d seconds",interval);
+        PR_Lock( notify_lock );
+        PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+        PR_Unlock( notify_lock );
+
+        if(interval < 14400){ /* 4 hour max */
+            interval = interval * 2;
+        } else {
+            interval = 14400;
+        }
+    } /* while */
+
+done:
+    if(agmt_not_notified){
+        /* failure */
+    	cleanruv_log(data->task, ABORT_CLEANALLRUV_ID,"Abort task failed, will resume the task at the next server startup.");
+    } else {
+        /*
+         *  Clean up the config
+         */
+        delete_aborted_rid(data->replica, data->rid, data->repl_root);
+        cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Successfully aborted cleanAllRUV task for rid(%d)", data->rid);
+    }
+    if(data->task){
+        slapi_task_finish(data->task, agmt_not_notified);
+    }
+    if(data->repl_obj && release_it)
+        object_release(data->repl_obj);
+    if(data->payload){
+        ber_bvfree(data->payload);
+    }
+    slapi_ch_free_string(&data->repl_root);
+    slapi_sdn_free(&data->sdn);
+    slapi_ch_free((void **)&data);
+}
+
+static int
+replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct berval *payload)
+{
+    Repl_Connection *conn = NULL;
+    ConnResult crc = 0;
+    int msgid = 0;
+    int rc = 0;
+
+    if((conn = conn_new(ra)) == NULL){
+        return -1;
+    }
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+        crc = conn_send_extended_operation(conn, REPL_ABORT_CLEANRUV_OID, payload, NULL, &msgid);
+        /*
+         * success or failure, just return the error code
+         */
+        rc = crc;
+        if(rc){
+        	cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to send extop to replica(%s).", agmt_get_long_name(ra));
+        }
+    } else {
+        cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to connect to replica(%s).", agmt_get_long_name(ra));
+        rc = -1;
+    }
+    conn_delete_internal_ext(conn);
+
+    return rc;
+}
+
+
+static int
+replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result)
+{
+    Repl_Connection *conn = NULL;
+    ConnResult crc = 0;
+    int msgid = 0;
+    int rc = 0;
+
+    if((conn = conn_new(ra)) == NULL){
+        return -1;
+    }
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+        crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, payload, NULL, &msgid);
+        if(crc == CONN_OPERATION_SUCCESS && check_result){
+            struct berval *retsdata = NULL;
+            char *retoid = NULL;
+
+            crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
+            if (CONN_OPERATION_SUCCESS == crc ){
+                struct berval **ruv_bervals = NULL;
+                struct berval *data = NULL;
+                char *data_guid = NULL;
+
+                decode_repl_ext_response(retsdata, &rc, &ruv_bervals, &data_guid, &data);
+                /* just free everything, we only wanted "rc" */
+                slapi_ch_free_string(&data_guid);
+                if(data)
+                    ber_bvfree(data);
+                if (ruv_bervals)
+                    ber_bvecfree(ruv_bervals);
+
+                if(rc == 0 ){ /* rc == 1 is success */
+                    cleanruv_log(task, CLEANALLRUV_ID,"Replica %s does not support the CLEANALLRUV task.  Sending replica CLEANRUV task...",
+                        slapi_sdn_get_dn(agmt_get_dn_byref(ra)));
+                    /*
+                     *  Ok, this replica doesn't know about CLEANALLRUV, so just manually
+                     *  add the CLEANRUV task to the replica.
+                     */
+                    replica_send_cleanruv_task(ra, rid, task);
+                } else {
+                    /* extop was accepted */
+                    rc = 0;
+                }
+                if (NULL != retoid)
+                    ldap_memfree(retoid);
+                if (NULL != retsdata)
+                    ber_bvfree(retsdata);
+            }
+            agmt_set_cleanruv_data(ra, rid, CLEANRUV_NOTIFIED);
+        } else {
+            /*
+             * success or failure, just return the error code
+             */
+            rc = crc;
+        }
+    } else {
+        rc =-1;
+    }
+    conn_delete_internal_ext(conn);
+
+    return rc;
+}
+
+static int
+replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task)
+{
+    Repl_Connection *conn = NULL;
+    LDAP *ld;
+    Slapi_DN *dn = agmt_get_replarea(agmt);
+    struct berval **vals;
+    LDAPMessage *result = NULL, *entry = NULL;
+    BerElement *ber;
+    char *attrs[2];
+    char *attr = NULL;
+    char *iter = NULL;
+    char *ruv_part = NULL;
+    int found_rid = 0;
+    int part_count = 0;
+    int rc = 0, i;
+
+    if((conn = conn_new(agmt)) == NULL){
+        return -1;
+    }
+
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+        attrs[0] = "nsds50ruv";
+        attrs[1] = NULL;
+        ld = conn_get_ldap(conn);
+        if(ld == NULL){
+            conn_delete_internal_ext(conn);
+            return -1;
+        }
+        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(dn), LDAP_SCOPE_SUBTREE,
+            "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
+            attrs, 0, NULL, NULL, NULL, 0, &result);
+        slapi_sdn_free(&dn);
+        if(rc != LDAP_SUCCESS){
+        	cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
+                "agmt (%s) error (%d), will retry later.", agmt_get_long_name(agmt), rc);
+            conn_delete_internal_ext(conn);
+            return -1;
+        }
+        entry = ldap_first_entry( ld, result );
+        if ( entry != NULL ) {
+            for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
+                /* make sure the attribute is nsds50ruv */
+                if(strcasecmp(attr,"nsds50ruv") != 0){
+                    ldap_memfree( attr );
+                    continue;
+                }
+                found_rid = 0;
+                if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
+                    for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
+                        /* look for this replica */
+                        if(strstr(vals[i]->bv_val, rid_text)){
+                            found_rid = 1;
+                            /* get the max csn compare it to our known max csn */
+                            ruv_part = ldap_utf8strtok_r(vals[i]->bv_val, " ", &iter);
+                            for(part_count = 1; ruv_part && part_count < 5; part_count++){
+                                ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
+                            }
+                            if(part_count == 5){
+                                /* we have the maxcsn */
+                                if(strcmp(ruv_part, maxcsn)){
+                                    /* we are not caught up yet, free, and return */
+                                    ldap_value_free_len(vals);
+                                    ldap_memfree( attr );
+                                    ldap_msgfree( result );
+                                    if(ber){
+                                        ber_free( ber, 0 );
+                                    }
+                                    conn_delete_internal_ext(conn);
+                                    return -1;
+                                } else {
+                                    /* ok this replica has all the updates from the deleted replica */
+                                    rc = 0;
+                                }
+                            } else {
+                                /* there is no maxcsn for this rid - treat it as caught up */
+                                rc = 0;
+                            }
+                        }
+                    }
+                    if(!found_rid){
+                        /* must have been cleaned already */
+                        rc = 0;
+                    }
+                    ldap_value_free_len(vals);
+                }
+                ldap_memfree( attr );
+            }
+            if ( ber != NULL ) {
+                ber_free( ber, 0 );
+            }
+        }
+        if(result)
+            ldap_msgfree( result );
+    } else {
+        rc = -1;
+    }
+    conn_delete_internal_ext(conn);
+
+    return rc;
+}
+
+static int
+replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
+{
+    Repl_Connection *conn = NULL;
+    LDAP *ld = NULL;
+    LDAPMessage *result = NULL;
+    int rc = 0;
+
+    if((conn = conn_new(agmt)) == NULL){
+        return -1;
+    }
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+        ld = conn_get_ldap(conn);
+        if(ld == NULL){
+            slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_task: failed to get LDAP "
+                "handle from the replication agmt (%s).  Moving on to the next agmt.\n",agmt_get_long_name(agmt));
+            conn_delete_internal_ext(conn);
+            return -1;
+        }
+        if(ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "objectclass=top",
+            NULL, 0, NULL, NULL, NULL, 0, &result) == LDAP_SUCCESS)
+        {
+            rc = 0;
+        } else {
+            rc = -1;
+        }
+        if(result)
+            ldap_msgfree( result );
+    } else {
+        rc = -1;
+    }
+    conn_delete_internal_ext(conn);
+
+    return rc;
 }
 
+static int
+replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task)
+{
+    Repl_Connection *conn = NULL;
+    BerElement *ber = NULL;
+    struct berval **vals = NULL;
+    LDAPMessage *result = NULL, *entry = NULL;
+    LDAP *ld = NULL;
+    Slapi_DN *dn = agmt_get_replarea(ra);
+    char *attrs[2];
+    char *attr = NULL;
+    int rc = 0, i;
+
+    if((conn = conn_new(ra)) == NULL){
+        return -1;
+    }
+    if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
+        attrs[0] = "nsds50ruv";
+        attrs[1] = NULL;
+        ld = conn_get_ldap(conn);
+        if(ld == NULL){
+        	cleanruv_log(task, CLEANALLRUV_ID,"Failed to get LDAP handle from "
+                "the replication agmt (%s).  Moving on to the next agmt.",agmt_get_long_name(ra));
+            rc = -1;
+            goto done;
+        }
+
+        rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(dn), LDAP_SCOPE_SUBTREE,
+            "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
+            attrs, 0, NULL, NULL, NULL, 0, &result);
+        slapi_sdn_free(&dn);
+        if(rc != LDAP_SUCCESS){
+            cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
+                "agmt (%s) error (%d), will retry later.", agmt_get_long_name(ra), rc);
+            rc = -1;
+            goto done;
+        }
+        entry = ldap_first_entry( ld, result );
+        if ( entry != NULL ) {
+            for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
+                /* make sure the attribute is nsds50ruv */
+                if(strcasecmp(attr,"nsds50ruv") != 0){
+                    ldap_memfree( attr );
+                    continue;
+                }
+                if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
+                    for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
+                        /* look for this replica */
+                        if(strstr(vals[i]->bv_val, rid_text)){
+                            /* rid has not been cleaned yet, free and return */
+                            rc = -1;
+                            ldap_value_free_len(vals);
+                            ldap_memfree( attr );
+                            if ( ber != NULL ) {
+                                ber_free( ber, 0 );
+                                ber = NULL;
+                            }
+                            goto done;
+                        } else {
+                            rc = 0;
+                        }
+                    }
+                    ldap_value_free_len(vals);
+                }
+                ldap_memfree( attr );
+            } /* for loop */
+            if ( ber != NULL ) {
+                ber_free( ber, 0 );
+            }
+        }
+done:
+        if(result)
+            ldap_msgfree( result );
+    } else {
+        return -1;
+    }
+    conn_delete_internal_ext(conn);
+
+    return rc;
+}
+
+static int
+get_cleanruv_task_count()
+{
+   int i, count = 0;
+
+   slapi_rwlock_wrlock(rid_lock);
+   for(i = 0; i < CLEANRIDSIZ; i++){
+       if(cleaned_rids[i] != 0){
+           count++;
+       }
+   }
+   slapi_rwlock_unlock(rid_lock);
+
+   return count;
+}
+
+static int
+get_abort_cleanruv_task_count()
+{
+   int i, count = 0;
+
+   slapi_rwlock_wrlock(rid_lock);
+   for(i = 0; i < CLEANRIDSIZ; i++){
+       if(aborted_rids[i] != 0){
+           count++;
+       }
+   }
+   slapi_rwlock_unlock(rid_lock);
+
+   return count;
+}
+
+/*
+ *  Notify sleeping CLEANALLRUV threads to stop
+ */
 void
-set_released_rid( int rid )
+stop_ruv_cleaning()
 {
-	released_rid = rid;
+    if(notify_lock){
+        PR_Lock( notify_lock );
+        PR_NotifyCondVar( notify_cvar );
+        PR_Unlock( notify_lock );
+    }
 }
 
+/*
+ *  Write our logging to the task and error log
+ */
 void
-delete_released_rid()
+cleanruv_log(Slapi_Task *task, char *task_type, char *fmt, ...)
 {
-	released_rid = 0;
+    va_list ap1;
+    va_list ap2;
+    va_list ap3;
+    va_list ap4;
+    char *errlog_fmt;
+
+    va_start(ap1, fmt);
+    va_start(ap2, fmt);
+    va_start(ap3, fmt);
+    va_start(ap4, fmt);
+
+    if(task){
+        slapi_task_log_notice_ext(task, fmt, ap1);
+        slapi_task_log_status_ext(task, fmt, ap2);
+        slapi_task_inc_progress(task);
+    }
+    errlog_fmt = PR_smprintf("%s: %s\n",task_type, fmt);
+    slapi_log_error_ext(SLAPI_LOG_FATAL, repl_plugin_name, errlog_fmt, ap3, ap4);
+    slapi_ch_free_string(&errlog_fmt);
+
+    va_end(ap1);
+    va_end(ap2);
+    va_end(ap3);
+    va_end(ap4);
 }
+
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index 9ad5c5a..fb8ea09 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -487,9 +487,9 @@ ruv_replace_replica_purl (RUV *ruv, ReplicaId rid, const char *replica_purl)
     replica = ruvGetReplica (ruv, rid);
     if (replica != NULL)
     {
-        if (strcmp(replica->replica_purl, replica_purl)) { /* purl updated */
+        if (replica->replica_purl == NULL || strcmp(replica->replica_purl, replica_purl)) { /* purl updated */
             /* Replace replica_purl in RUV since supplier has been updated. */
-            slapi_ch_free((void **)&(replica->replica_purl));
+            slapi_ch_free_string(&replica->replica_purl);
             replica->replica_purl = slapi_ch_strdup(replica_purl);
             /* Also, reset csn and min_csn. */
             replica->csn = replica->min_csn = NULL;
@@ -863,10 +863,6 @@ ruv_covers_csn_internal(const RUV *ruv, const CSN *csn, PRBool strict)
 	{
 		rid = csn_get_replicaid(csn);
 		replica = ruvGetReplica (ruv, rid);
-		if((is_released_rid(rid)) || (replica == NULL && is_already_released_rid()) ){
-			/* this is a released rid, so return true */
-			return PR_TRUE;
-		}
 		if (replica == NULL)
 		{
 			/*
@@ -930,7 +926,7 @@ ruv_covers_csn_strict(const RUV *ruv, const CSN *csn)
  * or max{maxcsns of all ruv elements} if get_the_max != 0.
  */
 static int
-ruv_get_min_or_max_csn(const RUV *ruv, CSN **csn, int get_the_max)
+ruv_get_min_or_max_csn(const RUV *ruv, CSN **csn, int get_the_max, ReplicaId rid)
 {
 	int return_value;
 
@@ -960,12 +956,18 @@ ruv_get_min_or_max_csn(const RUV *ruv, CSN **csn, int get_the_max)
 			{
 				continue;
 			}
-
-			if (found == NULL || 
-				(!get_the_max && csn_compare(found, replica->csn)>0) ||
-				( get_the_max && csn_compare(found, replica->csn)<0))
-			{
-				found = replica->csn;
+			if(rid){ /* we are only interested in this rid's maxcsn */
+				if(replica->rid == rid){
+					found = replica->csn;
+					break;
+				}
+			} else {
+				if (found == NULL ||
+					(!get_the_max && csn_compare(found, replica->csn)>0) ||
+					( get_the_max && csn_compare(found, replica->csn)<0))
+				{
+					found = replica->csn;
+				}
 			}
 		} 
 		if (found == NULL)
@@ -983,15 +985,20 @@ ruv_get_min_or_max_csn(const RUV *ruv, CSN **csn, int get_the_max)
 }
 
 int
+ruv_get_rid_max_csn(const RUV *ruv, CSN **csn, ReplicaId rid){
+	return ruv_get_min_or_max_csn(ruv, csn, 1 /* get the max */, rid);
+}
+
+int
 ruv_get_max_csn(const RUV *ruv, CSN **csn)
 {
-	return ruv_get_min_or_max_csn(ruv, csn, 1 /* get the max */);
+	return ruv_get_min_or_max_csn(ruv, csn, 1 /* get the max */, 0 /* rid */);
 }
 
 int
 ruv_get_min_csn(const RUV *ruv, CSN **csn)
 {
-	return ruv_get_min_or_max_csn(ruv, csn, 0 /* get the min */);
+	return ruv_get_min_or_max_csn(ruv, csn, 0 /* get the min */, 0 /* rid */);
 }
 
 int 
@@ -1097,6 +1104,22 @@ ruv_to_bervals(const RUV *ruv, struct berval ***bvals)
 	return return_value;
 }
 
+void
+ruv_get_cleaned_rids(RUV *ruv, ReplicaId *rids)
+{
+    RUVElement *replica;
+    int cookie;
+    int i = 0;
+
+    for (replica = dl_get_first (ruv->elements, &cookie); replica;
+         replica = dl_get_next (ruv->elements, &cookie))
+    {
+        if(is_cleaned_rid(replica->rid)){
+            rids[i++] = replica->rid;
+        }
+    }
+}
+
 int
 ruv_to_smod(const RUV *ruv, Slapi_Mod *smod)
 {
@@ -1428,15 +1451,14 @@ int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn)
     slapi_rwlock_wrlock (ruv->lock);
 
     if(is_cleaned_rid(rid)){
-        slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress: invalid replica ID"
-            "(%d), aborting update\n", rid);
         /* return success because we want to consume the update, but not perform it */
+        rc = RUV_COVERS_CSN;
         goto done;
     }
     replica = ruvGetReplica (ruv, rid);
     if (replica == NULL)
     {
-        replica = ruvAddReplicaNoCSN (ruv, csn_get_replicaid (csn), NULL/*purl*/);
+        replica = ruvAddReplicaNoCSN (ruv, rid, NULL/*purl*/);
         if (replica == NULL)
         {
             if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
diff --git a/ldap/servers/plugins/replication/repl5_ruv.h b/ldap/servers/plugins/replication/repl5_ruv.h
index d329dc3..f2d96f3 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.h
+++ b/ldap/servers/plugins/replication/repl5_ruv.h
@@ -117,6 +117,7 @@ PRBool ruv_covers_csn(const RUV *ruv, const CSN *csn);
 PRBool ruv_covers_csn_strict(const RUV *ruv, const CSN *csn);
 int ruv_get_min_csn(const RUV *ruv, CSN **csn);
 int ruv_get_max_csn(const RUV *ruv, CSN **csn);
+int ruv_get_rid_max_csn(const RUV *ruv, CSN **csn, ReplicaId rid);
 int ruv_enumerate_elements (const RUV *ruv, FNEnumRUV fn, void *arg);
 int ruv_to_smod(const RUV *ruv, Slapi_Mod *smod);
 int ruv_last_modified_to_smod(const RUV *ruv, Slapi_Mod *smod);
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
index f6378d2..88bb9e3 100644
--- a/ldap/servers/plugins/replication/repl_extop.c
+++ b/ldap/servers/plugins/replication/repl_extop.c
@@ -1338,7 +1338,7 @@ replica_config_get_mtnode_by_dn(const char *dn)
 /*
  * Decode the ber element passed to us by the cleanAllRUV task
  */
-static int
+int
 decode_cleanruv_payload(struct berval *extop_value, char **payload)
 {
 	BerElement *tmp_bere = NULL;
@@ -1373,313 +1373,313 @@ free_and_return:
 	return rc;
 }
 
-/*
- *  Process the REPL_CLEANRUV_OID extended operation.
- *
- *  The payload consists of the replica ID, and the repl root dn.  Since this is
- *  basically a replication operation, it could of originated here and bounced
- *  back from another master.  So check the rid against the "cleaned_rid".  If
- *  it's a match, then we were already here, and we can just return success.
- *
- *  Otherwise, we the set the cleaned_rid from the payload, fire off extended ops
- *  to all the replica agreements on this replica.  Then perform the actual
- *  cleanruv_task on this replica.
- */
 int
-multimaster_extop_cleanruv(Slapi_PBlock *pb){
+multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
+{
 	multimaster_mtnode_extension *mtnode_ext;
 	PRThread *thread = NULL;
-	Repl_Connection *conn;
-	const Slapi_DN *dn;
-	Replica *r = NULL;
-	Object *agmt_obj;
-	Repl_Agmt *agmt;
-	ConnResult crc;
-	cleanruv_data *data = NULL;
-	struct berval *extop_value;
+	cleanruv_data *data;
+	Replica *r;
+	ReplicaId rid;
+	CSN *maxcsn;
+	struct berval *extop_payload;
 	char *extop_oid;
 	char *repl_root;
 	char *payload = NULL;
 	char *iter;
-	int send_msgid = 0;
-	int agmt_count = 0;
-	int rid = 0;
 	int rc = 0;
 
 	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
-	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
 
 	if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_OID) != 0 ||
-	    NULL == extop_value || NULL == extop_value->bv_val){
+		NULL == extop_payload || NULL == extop_payload->bv_val){
 		/* something is wrong, error out */
-		return -1;
+		return LDAP_OPERATIONS_ERROR;
 	}
 	/*
-	 *  Extract the rid and repl_root from the payload
+	 *  Decode the payload, and grab our settings
 	 */
-	if(decode_cleanruv_payload(extop_value, &payload)){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to decode payload.  Aborting ext op\n");
-		return -1;
+	if(decode_cleanruv_payload(extop_payload, &payload)){
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: failed to decode payload.  Aborting ext op\n");
+		return LDAP_OPERATIONS_ERROR;
 	}
 	rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
 	repl_root = ldap_utf8strtok_r(iter, ":", &iter);
 
-	/*
-	 *  If we already cleaned this server, just return success
-	 */
-	if(is_cleaned_rid(rid)){
-		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_extop: rid (%d) has already been cleaned, skipping\n",rid);
-		return rc;
+	if(!is_cleaned_rid(rid) || is_task_aborted(rid)){
+		/* This replica has already been aborted, or was never cleaned, or already finished cleaning */
+		goto out;
 	} else {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: cleaning rid (%d)...\n", rid);
-		set_cleaned_rid(rid);
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: aborting cleanallruv task for rid(%d)\n", rid);
 	}
-
 	/*
 	 *  Get the node, so we can get the replica and its agreements
 	 */
 	if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to get replication node "
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: failed to get replication node "
 			"from (%s), aborting operation\n", repl_root);
-		return -1;
+		rc = LDAP_OPERATIONS_ERROR;
+		goto out;
 	}
-	if (mtnode_ext->replica)
+	if (mtnode_ext->replica){
 		object_acquire (mtnode_ext->replica);
-	if (mtnode_ext->replica == NULL){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: replica is missing from (%s), "
+	} else {
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: replica is missing from (%s), "
 			"aborting operation\n",repl_root);
 		rc = LDAP_OPERATIONS_ERROR;
-		goto free_and_return;
+		goto out;
 	}
 	r = (Replica*)object_get_data (mtnode_ext->replica);
+	if(r == NULL){
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort cleanAllRUV task: replica is NULL, aborting task\n");
+		rc = LDAP_OPERATIONS_ERROR;
+		goto out;
+	}
 	/*
-	 * Send out extended ops to each repl agreement
+	 *  Prepare the abort data
 	 */
-	agmt_obj = agmtlist_get_first_agreement_for_replica (r);
-	while (agmt_obj)
-	{
-		agmt = (Repl_Agmt*)object_get_data (agmt_obj);
-		if(!agmt_is_enabled(agmt)){
-			agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
-			continue;
-		}
-		dn = agmt_get_dn_byref(agmt);
-		conn = (Repl_Connection *)agmt_get_connection(agmt);
-		if(conn == NULL){
-			/* no connection for this agreement, move on to the next agmt */
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: the replica (%s), is "
-				"missing the connection.  This replica will not be cleaned.\n", slapi_sdn_get_dn(dn));
-			agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
-			continue;
-		}
-		crc = conn_connect(conn);
-		if (CONN_OPERATION_FAILED == crc ){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to connect "
-				"to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
-			rc = LDAP_OPERATIONS_ERROR;
-		} else if (CONN_SSL_NOT_ENABLED == crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to acquire "
-				"repl agmt connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
-			rc = LDAP_OPERATIONS_ERROR;
-		} else {
-			conn_cancel_linger(conn);
-			crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, extop_value, NULL, &send_msgid);
-			if (CONN_OPERATION_SUCCESS != crc){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to send "
-					"clean_ruv extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
-				rc = LDAP_OPERATIONS_ERROR;
-			} else {
-				/* success */
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: successfully sent "
-					"extended op to (%s)\n",slapi_sdn_get_dn(dn) );
-				agmt_count++;
-			}
-			conn_start_linger(conn);
-		}
-		if(crc != CONN_OPERATION_SUCCESS){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: replica (%s) has not "
-					        "been cleaned.  You will need to rerun the CLEANALLRUV task on this replica\n",
-					        slapi_sdn_get_dn(dn) );
-			rc = LDAP_OPERATIONS_ERROR;
-		}
-		agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
-	}
-
-	/* now clean the ruv */
-	replica_execute_cleanruv_task_ext(mtnode_ext->replica, rid);
-
-free_and_return:
-
-	if(rc == 0 && agmt_count > 0){
-		/*
-		 *  Launch the cleanruv monitoring thread.  Once all the replicas are cleaned it will release the rid
-		 */
-		data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
-		if (data == NULL) {
-			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to allocate "
-				"cleanruv_Data\n");
-			return -1;
-		}
-		data->repl_obj = mtnode_ext->replica;
-		data->rid = rid;
-
-		thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_monitor_thread,
-				(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
-				PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
-		if (thread == NULL) {
-			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: unable to create cleanAllRUV "
-				"monitoring thread.  Aborting task.\n");
+	data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
+	if (data == NULL) {
+		slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort cleanAllRUV task: failed to allocate "
+			"abort_cleanruv_data.  Aborting task.\n");
+		rc = LDAP_OPERATIONS_ERROR;
+		goto out;
+	}
+	data->repl_obj = mtnode_ext->replica; /* released in replica_abort_task_thread() */
+	data->replica = r;
+	data->task = NULL;
+	data->payload = slapi_ch_bvdup(extop_payload);
+	data->rid = rid;
+	data->repl_root = slapi_ch_strdup(repl_root);
+	/*
+	 *  Stop the cleaning, and delete the rid
+	 */
+	maxcsn = replica_get_cleanruv_maxcsn(r, rid);
+	delete_cleaned_rid(r, rid, maxcsn);
+	csn_free(&maxcsn);
+	add_aborted_rid(rid, r, repl_root);
+	stop_ruv_cleaning();
+	/*
+	 *  Send out the extended ops to the replicas
+	 */
+	thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
+			(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+			PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+	if (thread == NULL) {
+		if(mtnode_ext->replica){
+			object_release(mtnode_ext->replica);
 		}
-	} else if (rc == 0){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: Successfully Finished.\n");
-	} else {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanALLRUV_extop: failed to clean rid (%d), error (%d)\n",rid, rc);
+		slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "Abort cleanAllRUV task: unable to create abort "
+			"thread.  Aborting task.\n");
+		rc = LDAP_OPERATIONS_ERROR;
 	}
 
-	if (mtnode_ext->replica)
-		object_release (mtnode_ext->replica);
+out:
+    slapi_ch_free_string(&payload);
 
 	return rc;
 }
-
 /*
- *  Process the REPL_RELEASERUV_OID extended operation
+ *  Process the REPL_CLEANRUV_OID extended operation.
  *
- *  Once, all the replicas in the replication farm have been cleaned, then
- *  we need to "release" the cleaned_rid, or else we will reject all updates
- *  that come from that rid until we restart the server.
+ *  The payload consists of the replica ID, repl root dn, and the maxcsn.  Since this is
+ *  basically a replication operation, it could of originated here and bounced
+ *  back from another master.  So check the rid against the "cleaned_rid".  If
+ *  it's a match, then we were already here, and we can just return success.
  *
- *  We set the cleaned_ruv to zero(invalid rid), and then fire off extended
- *  operations to all of the replicas
+ *  Otherwise, we the set the cleaned_rid from the payload, fire off extended ops
+ *  to all the replica agreements on this replica.  Then perform the actual
+ *  cleanruv_task on this replica.
  */
 int
-multimaster_extop_releaseruv(Slapi_PBlock *pb){
+multimaster_extop_cleanruv(Slapi_PBlock *pb)
+{
 	multimaster_mtnode_extension *mtnode_ext;
-	Repl_Connection *conn;
-	const Slapi_DN *dn;
+	PRThread *thread = NULL;
 	Replica *r = NULL;
-	Object *agmt_obj;
-	Repl_Agmt *agmt;
-	ConnResult crc;
-	struct berval *extop_value;
-	char *payload = NULL;
+	cleanruv_data *data = NULL;
+	CSN *maxcsn;
+	struct berval *extop_payload;
+	struct berval *resp_bval = NULL;
+	BerElement *resp_bere = NULL;
 	char *extop_oid;
 	char *repl_root;
+	char *payload = NULL;
+	char *csnstr = NULL;
 	char *iter;
-	int send_msgid = 0;
+	int release_it = 0;
 	int rid = 0;
 	int rc = 0;
 
 	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
-	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_payload);
 
-	if (NULL == extop_oid || strcmp(extop_oid, REPL_RELEASERUV_OID) != 0 ||
-		NULL == extop_value || NULL == extop_value->bv_val){
+	if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_OID) != 0 ||
+	    NULL == extop_payload || NULL == extop_payload->bv_val){
 		/* something is wrong, error out */
-		return -1;
+		rc = -1;
+		goto free_and_return;
 	}
-
-	if(decode_cleanruv_payload(extop_value, &payload)){
-		slapi_log_error(SLAPI_LOG_FATAL,repl_plugin_name, "releaseRUV_extop: failed to decode payload, aborting ext op.\n");
-		return -1;
+	/*
+	 *  Decode the payload
+	 */
+	if(decode_cleanruv_payload(extop_payload, &payload)){
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to decode payload.  Aborting ext op\n");
+		rc = -1;
+		goto free_and_return;
 	}
 	rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
 	repl_root = ldap_utf8strtok_r(iter, ":", &iter);
-
+	csnstr = ldap_utf8strtok_r(iter, ":", &iter);
+	maxcsn = csn_new();
+	csn_init_by_string(maxcsn, csnstr);
 	/*
-	 *  If we already released this ruv, just return.
+	 *  If we already cleaned this server, just return success
 	 */
-	if(is_released_rid(rid) || is_already_released_rid()){
-		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_extop: rid (%d) has already been released, skipping.\n",rid);
-		return 0;
+	if(is_cleaned_rid(rid)){
+		csn_free(&maxcsn);
+		rc = 1;
+		goto free_and_return;
 	} else {
-		/* set the released rid, and trigger trimming */
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: releasing rid (%d)...\n", rid);
-		set_released_rid((int)rid);
-		trigger_cl_trimming();
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: cleaning rid (%d)...\n", rid);
 	}
 
+	/*
+	 *  Get the node, so we can get the replica and its agreements
+	 */
 	if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: failed to get node "
-			"from replication root dn(%s), aborting operation.\n", repl_root);
-		return -1;
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to get replication node "
+			"from (%s), aborting operation\n", repl_root);
+		rc = -1;
+		goto free_and_return;
 	}
-	if (mtnode_ext->replica)
+
+	if (mtnode_ext->replica){
 		object_acquire (mtnode_ext->replica);
+		release_it = 1;
+	}
 	if (mtnode_ext->replica == NULL){
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: replica is missing from (%s), "
-			"aborting operation.\n", repl_root);
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is missing from (%s), "
+			"aborting operation\n",repl_root);
 		rc = LDAP_OPERATIONS_ERROR;
 		goto free_and_return;
 	}
+
 	r = (Replica*)object_get_data (mtnode_ext->replica);
-	/*
-	 *  Loop over the agreements, and send out extended ops
-	 */
-	agmt_obj = agmtlist_get_first_agreement_for_replica (r);
-	while (agmt_obj)
-	{
-		agmt = (Repl_Agmt*)object_get_data (agmt_obj);
-		if(!agmt_is_enabled(agmt)){
-			agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
-			continue;
+	if(r == NULL){
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is NULL, aborting task\n");
+		rc = -1;
+		goto free_and_return;
+	}
+
+	if(replica_get_type(r) != REPLICA_TYPE_READONLY){
+		/*
+		 *  Launch the cleanruv monitoring thread.  Once all the replicas are cleaned it will release the rid
+		 *
+		 *  This will also release mtnode_ext->replica
+		 */
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: launching cleanAllRUV thread...\n");
+		data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
+		if (data == NULL) {
+			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to allocate "
+				"cleanruv_Data\n");
+			rc = -1;
+			goto free_and_return;
 		}
-		dn = agmt_get_dn_byref(agmt);
-		conn = (Repl_Connection *)agmt_get_connection(agmt);
-		if(conn == NULL){
-			/* no connection for this agreement, log error, and move on */
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: the replica (%s), is "
-				"missing the connection.  This replica will not be released.\n", slapi_sdn_get_dn(dn));
-			agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
-			continue;
+		data->repl_obj = mtnode_ext->replica;
+		data->replica = r;
+		data->rid = rid;
+		data->task = NULL;
+		data->maxcsn = maxcsn;
+		data->payload = slapi_ch_bvdup(extop_payload);
+
+		thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
+				(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+				PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+		if (thread == NULL) {
+		    rc = -1;
+			slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: unable to create cleanAllRUV "
+				"monitoring thread.  Aborting task.\n");
 		}
-		crc = conn_connect(conn);
-		if (CONN_OPERATION_FAILED == crc ){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: failed to connect "
-				"to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
-			rc = LDAP_OPERATIONS_ERROR;
-		} else if (CONN_SSL_NOT_ENABLED == crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: failed to acquire "
-				"repl agmt connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
-			rc = LDAP_OPERATIONS_ERROR;
-		} else {
-			conn_cancel_linger(conn);
-			crc = conn_send_extended_operation(conn, REPL_RELEASERUV_OID, extop_value, NULL, &send_msgid);
-			if (CONN_OPERATION_SUCCESS != crc){
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to send "
-					"releaseRUV extended op to repl agmt (%s), error %d\n",	slapi_sdn_get_dn(dn), crc);
-				rc = LDAP_OPERATIONS_ERROR;
+	} else { /* this is a read-only consumer */
+		/*
+		 * wait for the maxcsn to be covered
+		 */
+		Object *ruv_obj;
+		const RUV *ruv;
+
+		ruv_obj = replica_get_ruv(r);
+		ruv = object_get_data (ruv_obj);
+
+		while(!is_task_aborted(rid) && !slapi_is_shutting_down()){
+			if(!ruv_contains_replica(ruv, rid)){
+				/* we've already been cleaned */
+				break;
+			}
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: checking if we're caught up...\n");
+			if(ruv_covers_csn(ruv,maxcsn) || csn_get_replicaid(maxcsn) == 0){
+				/* We are caught up */
+				break;
 			} else {
-				/* success */
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: successfully sent "
-					"releaseRUV extended op to (%s)\n",slapi_sdn_get_dn(dn) );
-				rc = 0;
+				char csnstr[CSN_STRSIZE];
+				csn_as_string(maxcsn, PR_FALSE, csnstr);
+				slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: not ruv caught up maxcsn(%s)\n", csnstr);
 			}
-			conn_start_linger(conn);
-		}
-		if(crc){
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: replica (%s) has not "
-				"been released.  You will need to rerun the task.\n",
-				slapi_sdn_get_dn(dn) );
+			DS_Sleep(PR_SecondsToInterval(5));
 		}
-		agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: we're caught up...\n");
+		/*
+		 *  Set cleaned rid in memory only - does not survive a server restart
+		 */
+		set_cleaned_rid(rid);
+		/*
+		 *  Clean the ruv
+		 */
+		replica_execute_cleanruv_task_ext(mtnode_ext->replica, rid);
+
+		/* free everything */
+		object_release(ruv_obj);
+		csn_free(&maxcsn);
+		if (mtnode_ext->replica && release_it)
+			object_release (mtnode_ext->replica);
+		/*
+		 *  This read-only replica has no easy way to tell when it's safe to release the rid.
+		 *  So we won't release it, not until a server restart.
+		 */
+		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);
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Successfully cleaned rid(%d).\n", rid);
 	}
 
 free_and_return:
+	if(rc && release_it){
+		if (mtnode_ext->replica)
+			object_release (mtnode_ext->replica);
+	}
+	slapi_ch_free_string(&payload);
+
 	/*
-	 *  Set the rid as "ALREADY_RELEASED, and remove the cleaned ruv
+	 *   Craft a message so we know this replica supports the task
 	 */
-	if(rc == 0){
-		set_released_rid(ALREADY_RELEASED);
-		delete_cleaned_rid();
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: Successfully released rid (%d)\n", rid);
-	} else {
-		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: Failed to release rid(%d), error (%d), "
-			"please retry the task.\n",rid, rc);
-	}
+	if ((resp_bere = der_alloc())){
 
-	if(mtnode_ext->replica)
-		object_release (mtnode_ext->replica);
+		ber_int_t response = 1;
+
+		ber_printf(resp_bere, "{e}", response);
+		ber_flatten(resp_bere, &resp_bval);
+		slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
+		slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+		/* resp_bere */
+		if (NULL != resp_bere)
+		{
+			ber_free(resp_bere, 1);
+		}
+		/* resp_bval */
+		if (NULL != resp_bval)
+		{
+			ber_bvfree(resp_bval);
+		}
+	}
 
 	return rc;
 }
diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c
index 9445394..383d562 100644
--- a/ldap/servers/plugins/replication/repl_globals.c
+++ b/ldap/servers/plugins/replication/repl_globals.c
@@ -110,6 +110,8 @@ const char *type_replicaChangeCount = "nsds5ReplicaChangeCount";
 const char *type_replicaTombstonePurgeInterval = "nsds5ReplicaTombstonePurgeInterval";
 const char *type_replicaLegacyConsumer = "nsds5ReplicaLegacyConsumer";
 const char *type_ruvElementUpdatetime = "nsruvReplicaLastModified";
+const char *type_replicaCleanRUV = "nsds5ReplicaCleanRUV";
+const char *type_replicaAbortCleanRUV = "nsds5ReplicaAbortCleanRUV";
 
 /* Attribute names for replication agreement attributes */
 const char *type_nsds5ReplicaHost = "nsds5ReplicaHost";
@@ -128,6 +130,7 @@ const char *type_nsds5ReplicaBusyWaitTime = "nsds5ReplicaBusyWaitTime";
 const char *type_nsds5ReplicaSessionPauseTime = "nsds5ReplicaSessionPauseTime";
 const char *type_nsds5ReplicaEnabled = "nsds5ReplicaEnabled";
 const char *type_nsds5ReplicaStripAttrs = "nsds5ReplicaStripAttrs";
+const char *type_nsds5ReplicaCleanRUVnotified = "nsds5ReplicaCleanRUVNotified";
 
 /* windows sync specific attributes */
 const char *type_nsds7WindowsReplicaArea = "nsds7WindowsReplicaSubtree";
@@ -139,7 +142,7 @@ const char *type_nsds7DirsyncCookie = "nsds7DirsyncCookie";
 const char *type_winSyncInterval = "winSyncInterval";
 const char *type_oneWaySync = "oneWaySync";
 
-/* To Allow Consumer Initialisation when adding an agreement - */
+/* To Allow Consumer Initialization when adding an agreement - */
 const char *type_nsds5BeginReplicaRefresh = "nsds5BeginReplicaRefresh";
 
 static int repl_active_threads;
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index 2ffd1f6..e622485 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -1969,6 +1969,33 @@ slapi_log_error( int severity, char *subsystem, char *fmt, ... )
 }
 
 int
+slapi_log_error_ext(int severity, char *subsystem, char *fmt, va_list varg1, va_list varg2)
+{
+    int rc = 0;
+
+    if ( severity < SLAPI_LOG_MIN || severity > SLAPI_LOG_MAX ) {
+        (void)slapd_log_error_proc( subsystem, "slapi_log_error: invalid severity %d (message %s)\n",
+            severity, fmt );
+            return( -1 );
+    }
+
+    if (
+    #ifdef _WIN32
+        *module_ldap_debug
+    #else
+        slapd_ldap_debug
+    #endif
+        & slapi_log_map[ severity ] )
+    {
+	    rc = slapd_log_error_proc_internal( subsystem, fmt, varg1, varg2 );
+    } else {
+        rc = 0;        /* nothing to be logged --> always return success */
+    }
+
+    return( rc );
+}
+
+int
 slapi_is_loglevel_set ( const int loglevel )
 {
 
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index dc3fd38..f238bef 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5580,6 +5580,7 @@ int slapi_log_error( int severity, char *subsystem, char *fmt, ... )
 #else
         ;
 #endif
+int slapi_log_error_ext( int severity, char *subsystem, char *fmt, va_list varg1, va_list varg2);
 
 /* allowed values for the "severity" parameter */
 #define SLAPI_LOG_FATAL          	0
@@ -6090,6 +6091,8 @@ void slapi_task_log_notice(Slapi_Task *task, char *format, ...)
 #else
         ;
 #endif
+void slapi_task_log_status_ext(Slapi_Task *task, char *format, va_list varg);
+void slapi_task_log_notice_ext(Slapi_Task *task, char *format, va_list varg);
 
 /*
  * slapi_new_task: create new task, fill in DN, and setup modify callback
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 6d60775..5fc0b08 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -215,6 +215,17 @@ void slapi_task_log_status(Slapi_Task *task, char *format, ...)
     slapi_task_status_changed(task);
 }
 
+void slapi_task_log_status_ext(Slapi_Task *task, char *format, va_list ap)
+{
+    if (! task->task_status)
+        task->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER);
+    if (! task->task_status)
+        return;        /* out of memory? */
+
+    PR_vsnprintf(task->task_status, (10 * LOG_BUFFER), format, ap);
+    slapi_task_status_changed(task);
+}
+
 /* this adds a line to the 'nsTaskLog' value, which is cumulative (anything
  * logged here is added to the end)
  */
@@ -266,6 +277,51 @@ void slapi_task_log_notice(Slapi_Task *task, char *format, ...)
     slapi_task_status_changed(task);
 }
 
+void slapi_task_log_notice_ext(Slapi_Task *task, char *format, va_list ap)
+{
+    char buffer[LOG_BUFFER];
+    size_t len;
+
+    PR_vsnprintf(buffer, LOG_BUFFER, format, ap);
+
+    if (task->task_log_lock) {
+        PR_Lock(task->task_log_lock);
+    }
+    len = 2 + strlen(buffer) + (task->task_log ? strlen(task->task_log) : 0);
+    if ((len > MAX_SCROLLBACK_BUFFER) && task->task_log) {
+        size_t i;
+        char *newbuf;
+
+        /* start from middle of buffer, and find next linefeed */
+        i = strlen(task->task_log)/2;
+        while (task->task_log[i] && (task->task_log[i] != '\n'))
+            i++;
+        if (task->task_log[i])
+            i++;
+        len = strlen(task->task_log) - i + 2 + strlen(buffer);
+        newbuf = (char *)slapi_ch_malloc(len);
+        strcpy(newbuf, task->task_log + i);
+        slapi_ch_free((void **)&task->task_log);
+        task->task_log = newbuf;
+    } else {
+        if (! task->task_log) {
+            task->task_log = (char *)slapi_ch_malloc(len);
+            task->task_log[0] = 0;
+        } else {
+            task->task_log = (char *)slapi_ch_realloc(task->task_log, len);
+        }
+    }
+
+    if (task->task_log[0])
+        strcat(task->task_log, "\n");
+    strcat(task->task_log, buffer);
+    if (task->task_log_lock) {
+        PR_Unlock(task->task_log_lock);
+    }
+
+    slapi_task_status_changed(task);
+}
+
 /* update attributes in the entry under "cn=tasks" to match the current
  * status of the task. */
 void slapi_task_status_changed(Slapi_Task *task)


commit 0d453f2e31cdfff0ad68b0393edcc87fd58acde6
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed Aug 1 15:45:21 2012 -0400

    Ticket 413 - "Server is unwilling to perform" when running ldapmodify on nsds5ReplicaStripAttrs
    
    Bug Description:  trying to set nsds5ReplicaStripAttrs yields an error 53
    
    Fix Description:  Needed to check for this new attribute when in the agmtlist modify
                      callback.  When it doesn't recognize the attribute it returns error 53.
    
    https://fedorahosted.org/389/ticket/413
    
    Reviewed by: Richm(Thanks!)
    (cherry picked from commit e86013506df7f3da280d67be2b3bd9ab24b241bf)

diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index b04d9c4..d7ba6a6 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -358,6 +358,7 @@ int agmt_has_protocol(Repl_Agmt *agmt);
 PRBool agmt_is_enabled(Repl_Agmt *ra);
 int agmt_set_enabled_from_entry(Repl_Agmt *ra, Slapi_Entry *e);
 char **agmt_get_attrs_to_strip(Repl_Agmt *ra);
+int agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e);
 
 typedef struct replica Replica;
 
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 4beb13a..2978aba 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -2547,3 +2547,27 @@ agmt_get_attrs_to_strip(Repl_Agmt *ra)
 		return NULL;
 	}
 }
+
+int
+agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e)
+{
+    char *tmpstr = NULL;
+
+    PR_Lock(ra->lock);
+
+    tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaStripAttrs);
+    if (NULL != tmpstr){
+        if(ra->attrs_to_strip){
+            slapi_ch_array_free(&ra->attrs_to_strip);
+        }
+        ra->attrs_to_strip = slapi_str2charray_ext(tmpstr, " ", 0);
+        PR_Unlock(ra->lock);
+        prot_notify_agmt_changed(ra->protocol, ra->long_name);
+        slapi_ch_free_string(&tmpstr);
+        return 0;
+    }
+
+    PR_Unlock(ra->lock);
+
+    return -1;
+}
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index 1c18a85..86f06bf 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -499,6 +499,15 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
                 rc = SLAPI_DSE_CALLBACK_ERROR;
             }
         }
+        else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaStripAttrs))
+        {
+            if(agmt_set_attrs_to_strip(agmt, e) != 0){
+                slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+                    "failed to set replica agmt attributes to strip for %s\n",agmt_get_long_name(agmt));
+                *returncode = LDAP_OPERATIONS_ERROR;
+                rc = SLAPI_DSE_CALLBACK_ERROR;
+            }
+        }
         else if (0 == windows_handle_modify_agreement(agmt, mods[i]->mod_type, e))
         {
             slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " 


commit 3168f04d96f962b0c506d0ee676acc9056566514
Author: Noriko Hosoi <nhosoi at totoro.usersys.redhat.com>
Date:   Tue Jul 17 16:58:47 2012 -0700

    Coverity defects
    
    12811: Unused pointer value
           preop_modrdn (plugins/uiduniq/uid.c)
           Removed unused variable "dn".
    
    12812: Unused pointer value
           ldbm_back_next_search_entry_ext (slapd/back-ldbm/ldbm_search.c)
           Removed unused variable "base".
    
    12813: Uninitialized pointer read
           string_values2keys (plugins/syntaxes/string.c)
           Commit f6b74ad18a52720c4558d4a46cbb2eeb21109033 missed to set
           an value bvp for the newly added case ((syntax & SYNTAX_DN) &&
           (value_flags & SLAPI_ATTR_FLAG_NORMALIZED_CES)), which caused
           the uninitialized pointer read.  This patch sets bvp for all
           3 cases.
    (cherry picked from commit c952e16707a6a0ad98c6985484b58d0844fb8aa0)

diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c
index ebe6b63..d9e6ba4 100644
--- a/ldap/servers/plugins/uiduniq/uid.c
+++ b/ldap/servers/plugins/uiduniq/uid.c
@@ -862,7 +862,6 @@ preop_modrdn(Slapi_PBlock *pb)
     int err;
     char *markerObjectClass=NULL;
     char *requiredObjectClass=NULL;
-    const char *dn = NULL;
     Slapi_DN *sdn = NULL;
     Slapi_DN *superior;
     char *rdn;
@@ -913,8 +912,6 @@ preop_modrdn(Slapi_PBlock *pb)
     err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET_SDN, &sdn);
     if (err) { result = uid_op_error(31); break; }
 
-    dn = slapi_sdn_get_dn(sdn);
-
     /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */
     err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &superior);
     if (err) { result = uid_op_error(32); break; }
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 97eac2b..5fbea24 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -1327,7 +1327,6 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
     int                    managedsait;
     Slapi_Attr             *attr;
     Slapi_Filter           *filter;
-    const char             *base;
     back_search_result_set *sr;
     ID                     id;
     struct backentry       *e;
@@ -1380,7 +1379,6 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
                                "Null target DN", 0, NULL );
         return( -1 );
     }
-    base = slapi_sdn_get_dn(basesdn);
 
     if (sr->sr_current_sizelimit >= 0) {
         /* 


commit 5ff0a02468c530403b55a4a1d3555cf20a8db904
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed Jun 13 18:41:47 2012 -0400

    COVERITY FIXES
    
    12762
    12763
    12764
    12765
    12766
    12767
    12768
    12769
    12771
    
    Reviewed by: Noriko & Richm (Thanks!)

diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
index 5816837..202cb64 100644
--- a/ldap/servers/plugins/replication/cl5_clcache.c
+++ b/ldap/servers/plugins/replication/cl5_clcache.c
@@ -680,6 +680,7 @@ clcache_skip_change ( CLC_Buffer *buf )
 				 */
 				skip = 0;
 			}
+			csn_free(&cons_maxcsn);
 			break;
 		}
 
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index a5d608a..771af61 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -1176,7 +1176,7 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, char *returntext)
 {
 	PRThread *thread = NULL;
 	Repl_Connection *conn;
-	Replica *replica = (Replica*)object_get_data (r);
+	Replica *replica;
 	Object *agmt_obj;
 	Repl_Agmt *agmt;
 	ConnResult crc;
@@ -1189,7 +1189,16 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, char *returntext)
 	int rc = 0;
 
 	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: cleaning rid (%d)...\n",(int)rid);
-	set_cleaned_rid(rid);
+
+	/*
+	 *  Grab the replica
+	 */
+	if(r){
+		replica = (Replica*)object_get_data (r);
+	} else {
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: replica is NULL, aborting task\n");
+		return -1;
+	}
 	/*
 	 *  Create payload
 	 */
@@ -1197,9 +1206,13 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, char *returntext)
 	payload = create_ruv_payload(ridstr);
 	if(payload == NULL){
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: failed to create ext op payload, aborting task\n");
-		goto done;
+		slapi_ch_free_string(&ridstr);
+		return -1;
 	}
 
+
+	set_cleaned_rid(rid);
+
 	agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
 	while (agmt_obj)
 	{
@@ -1245,11 +1258,12 @@ replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, char *returntext)
 		agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
 	}
 
-done:
-
-	if(payload)
+	/*
+	 *  We're done with the payload, free it.
+	 */
+	if(payload){
 		ber_bvfree(payload);
-
+	}
 	slapi_ch_free_string(&ridstr);
 
 	/*
diff --git a/ldap/servers/plugins/rootdn_access/rootdn_access.c b/ldap/servers/plugins/rootdn_access/rootdn_access.c
index 7fb5615..19e578c 100644
--- a/ldap/servers/plugins/rootdn_access/rootdn_access.c
+++ b/ldap/servers/plugins/rootdn_access/rootdn_access.c
@@ -217,7 +217,8 @@ static int
 rootdn_load_config(Slapi_PBlock *pb)
 {
     Slapi_Entry *e = NULL;
-    char *openTime, *closeTime;
+    char *openTime = NULL;
+    char *closeTime = NULL;
     char hour[3], min[3];
     int result = 0;
     int i;
@@ -243,7 +244,8 @@ rootdn_load_config(Slapi_PBlock *pb)
                 slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
                     "invalid rootdn-days-allowed value (%s), must be all letters, and comma separators\n",closeTime);
                 slapi_ch_free_string(&daysAllowed);
-                return -1;
+                result = -1;
+                goto free_and_return;
             }
             daysAllowed = strToLower(daysAllowed);
         }
@@ -251,14 +253,14 @@ rootdn_load_config(Slapi_PBlock *pb)
             if (strcspn(openTime, "0123456789")){
                 slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
                     "invalid rootdn-open-time value (%s), must be all digits\n",openTime);
-                slapi_ch_free_string(&openTime);
-                return -1;
+                result = -1;
+                goto free_and_return;
             }
             if(strlen(openTime) != 4){
                 slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
                     "invalid format for rootdn-open-time value (%s).  Should be HHMM\n", openTime);
-                slapi_ch_free_string(&openTime);
-                return -1;
+                result = -1;
+                goto free_and_return;
             }
             /*
              *  convert the time to all seconds
@@ -271,14 +273,14 @@ rootdn_load_config(Slapi_PBlock *pb)
             if (strcspn(closeTime, "0123456789")){
                 slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
                     "invalid rootdn-open-time value (%s), must be all digits, and should be HHMM\n",closeTime);
-                slapi_ch_free_string(&closeTime);
-                return -1;
+                result = -1;
+                goto free_and_return;
             }
             if(strlen(closeTime) != 4){
                 slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
                     "invalid format for rootdn-open-time value (%s), should be HHMM\n", closeTime);
-                slapi_ch_free_string(&closeTime);
-                return -1;
+                result = -1;
+                goto free_and_return;
             }
             /*
              *  convert the time to all seconds
@@ -294,13 +296,15 @@ rootdn_load_config(Slapi_PBlock *pb)
                 "there must be a open and a close time\n");
             slapi_ch_free_string(&closeTime);
             slapi_ch_free_string(&openTime);
-            return -1;
+            result = -1;
+            goto free_and_return;
         }
         if(close_time && open_time && close_time <= open_time){
             /* Make sure the closing time is greater than the open time */
             slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
                 "the close time must be greater than the open time\n");
             result = -1;
+            goto free_and_return;
         }
         if(hosts){
             for(i = 0; hosts[i] != NULL; i++){
@@ -370,13 +374,15 @@ rootdn_load_config(Slapi_PBlock *pb)
                 }
             }
         }
-        slapi_ch_free_string(&openTime);
-        slapi_ch_free_string(&closeTime);
     } else {
         /* failed to get the plugin entry */
         result = -1;
     }
 
+free_and_return:
+    slapi_ch_free_string(&openTime);
+    slapi_ch_free_string(&closeTime);
+
     slapi_log_error(SLAPI_LOG_PLUGIN, ROOTDN_PLUGIN_SUBSYSTEM, "<-- rootdn_load_config (%d)\n", result);
 
     return result;
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index de84700..1c81a1b 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -1058,8 +1058,8 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
     }
     if (!add_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID), newe, NULL)) {
        LOG("entry cache replace: can't add id\n", 0, 0, 0);
-       if (remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn))) {
-           LOG("entry cache replace: can't remove dn after add id failed\n", 0, 0, 0);
+       if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
+    	   LOG("entry cache replace: failed to remove dn table\n", 0, 0, 0);
        }
        PR_Unlock(cache->c_mutex);
        return 1;
@@ -1068,8 +1068,12 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
     if (newuuid && !add_hash(cache->c_uuidtable, (void *)newuuid, strlen(newuuid),
                        newe, NULL)) {
        LOG("entry cache replace: can't add uuid\n", 0, 0, 0);
-       remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn));
-       remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID));
+       if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
+    	   LOG("entry cache replace: failed to remove dn table(uuid cache)\n", 0, 0, 0);
+       }
+       if(remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID)) == 0){
+    	   LOG("entry cache replace: failed to remove id table(uuid cache)\n", 0, 0, 0);
+       }
        PR_Unlock(cache->c_mutex);
        return 1;
     }
@@ -1359,8 +1363,8 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
                 PR_Unlock(cache->c_mutex);
                 return 0;
             }
-            if (remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn))) {
-                LOG("=>= entrycache_add_int could not remove existing id from dn cache\n", 0, 0, 0);
+            if(remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn)) == 0){
+            	LOG("entrycache_add_int: failed to remove dn table\n", 0, 0, 0);
             }
             e->ep_state |= ENTRY_STATE_NOTINCACHE;
             PR_Unlock(cache->c_mutex);
@@ -1373,8 +1377,12 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
                    NULL)) {
                 LOG("entry %s already in uuid cache!\n", backentry_get_ndn(e),
                             0, 0);
-                remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn));
-                remove_hash(cache->c_idtable, &(e->ep_id), sizeof(ID));
+                if(remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn)) == 0){
+                	LOG("entrycache_add_int: failed to remove dn table(uuid cache)\n", 0, 0, 0);
+                }
+                if(remove_hash(cache->c_idtable, &(e->ep_id), sizeof(ID)) == 0){
+                	LOG("entrycache_add_int: failed to remove id table(uuid cache)\n", 0, 0, 0);
+                }
                 e->ep_state |= ENTRY_STATE_NOTINCACHE;
                 PR_Unlock(cache->c_mutex);
                 return -1;
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
index e6141d2..5452d6b 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -3909,7 +3909,7 @@ static int txn_test_threadmain(void *param)
     txn_test_iter **ttilist = NULL;
     size_t tticnt = 0;
     DB_TXN *txn = NULL;
-    txn_test_cfg cfg;
+    txn_test_cfg cfg = {0};
     size_t counter = 0;
     char keybuf[8192];
     char databuf[8192];
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
index 0541543..e50b930 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
@@ -2170,8 +2170,8 @@ _entryrdn_replace_suffix_id(DBC *cursor, DBT *key, DBT *adddata,
     char *realkeybuf = NULL;
     DBT realkey;
     char buffer[RDN_BULK_FETCH_BUFFER_SIZE]; 
-    DBT data;
-    DBT moddata;
+    DBT data = {0};
+    DBT moddata = {0};
     rdn_elem **childelems = NULL;
     rdn_elem **cep = NULL;
     rdn_elem *childelem = NULL;
@@ -2217,7 +2217,6 @@ _entryrdn_replace_suffix_id(DBC *cursor, DBT *key, DBT *adddata,
     key->flags = DB_DBT_USERMEM;    
 
     /* Setting the bulk fetch buffer */
-    memset(&data, 0, sizeof(data));
     data.ulen = sizeof(buffer);
     data.size = sizeof(buffer);
     data.data = buffer;
@@ -2228,7 +2227,6 @@ _entryrdn_replace_suffix_id(DBC *cursor, DBT *key, DBT *adddata,
     realkey.size = realkey.ulen = strlen(realkeybuf) + 1;
     realkey.flags = DB_DBT_USERMEM;    
 
-    memset(&moddata, 0, sizeof(moddata));
     moddata.flags = DB_DBT_USERMEM;
 
     for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {


commit 9c0605a84ef6c1e8e3120bd0a934b1be485f95b9
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Tue Jun 12 16:32:32 2012 -0400

    Ticket #388 - Improve replication agreement status messages
    
    Bug Description:  Result codes that were negative values triggered a generic error
                      message (System Error).  This is because of mozLDAP's ldap_err2string()
                      which can only handle positive values, but openldap's ldap_err2string
                      can handle both positive and negative numbers.
    
    Fix Description:  Created a wrapper function (slapi_err2string), that can handle both
                      positive and negative error codes, regardless which ldap library is
                      being used.
    
    Reviewed by:
    
    https://fedorahosted.org/389/ticket/388
    (cherry picked from commit 8f21ac81cfe8bf70b555ae011c9e7ff953deeb8e)

diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 4db7e13..4beb13a 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -2098,6 +2098,7 @@ agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *
 		else if (ldaprc != LDAP_SUCCESS)
 		{
 			char *replmsg = NULL;
+
 			if ( replrc ) {
 				replmsg = protocol_response2string(replrc);
 				/* Do not mix the unknown replication error with the known ldap one */
@@ -2105,19 +2106,9 @@ agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *
 					replmsg = NULL;
 				}
 			}
-			if (ldaprc > 0) {
-				PR_snprintf(ra->last_update_status, STATUS_LEN,
-							"%d %s%sLDAP error: %s%s%s",
-							ldaprc, 
-							message?message:"",message?"":" - ",
-							ldap_err2string(ldaprc),
-							replmsg ? " - " : "", replmsg ? replmsg : "");
-			} else { /* ldaprc is < 0 */
-				PR_snprintf(ra->last_update_status, STATUS_LEN,
-							"%d %s%sSystem error%s%s",
-							ldaprc,message?message:"",message?"":" - ",
-							replmsg ? " - " : "", replmsg ? replmsg : "");
-			}
+			PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s%sLDAP error: %s%s%s",
+				ldaprc, message?message:"",message?"":" - ",
+				slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "");
 		}
 		/* ldaprc == LDAP_SUCCESS */
 		else if (replrc != 0)
@@ -2175,6 +2166,7 @@ agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *me
 		if (ldaprc != LDAP_SUCCESS)
 		{
 			char *replmsg = NULL;
+
 			if ( replrc ) {
 				replmsg = protocol_response2string(replrc);
 				/* Do not mix the unknown replication error with the known ldap one */
@@ -2182,19 +2174,9 @@ agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *me
 					replmsg = NULL;
 				}
 			}
-			if (ldaprc > 0) {
-				PR_snprintf(ra->last_init_status, STATUS_LEN,
-							"%d %s%sLDAP error: %s%s%s",
-							ldaprc, 
-							message?message:"",message?"":" - ",
-							ldap_err2string(ldaprc),
-							replmsg ? " - " : "", replmsg ? replmsg : "");
-			} else { /* ldaprc is < 0 */
-				PR_snprintf(ra->last_init_status, STATUS_LEN,
-							"%d %s%sSystem error%s%s",
-							ldaprc,message?message:"",message?"":" - ",
-							replmsg ? " - " : "", replmsg ? replmsg : "");
-			}
+			PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s%sLDAP error: %s%s%s",
+				ldaprc, message?message:"",message?"":" - ",
+				slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "");
 		}
 		/* ldaprc == LDAP_SUCCESS */
 		else if (replrc != 0)
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 3589f08..3226ede 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -6546,3 +6546,61 @@ config_set_auditlog_enabled(int value){
     }
     CFG_UNLOCK_WRITE(slapdFrontendConfig);
 }
+
+char *
+slapi_err2string(int result)
+{
+    /*
+     *  If we are using openldap, then we can safely use ldap_err2string with
+     *  positive and negative result codes.  MozLDAP's ldap_err2string can
+     *  only handle positive result codes.
+     */
+#if defined (USE_OPENLDAP)
+    return ldap_err2string(result);
+#else
+    if(result >= 0){
+        return ldap_err2string(result);
+    }
+    switch (result)
+    {
+        case -1:
+            return ("Can't contact LDAP server");
+        case -2:
+            return ("Local error");
+        case -3:
+            return ("Encoding error");
+        case -4:
+            return ("Decoding error");
+        case -5:
+            return ("Timed out");
+        case -6:
+            return ("Unknown authentication method");
+        case -7:
+            return ("Bad search filter");
+        case -8:
+            return ("User canceled operation");
+        case -9:
+            return ("Bad parameter to an ldap routine");
+        case -10:
+            return ("Out of memory");
+        case -11:
+            return ("Connect error");
+        case -12:
+            return ("Not Supported");
+        case -13:
+            return ("Control not found");
+        case -14:
+            return ("No results returned");
+        case -15:
+            return ("More results to return");
+        case -16:
+            return ("Client Loop");
+        case -17:
+            return ("Referral Limit Exceeded");
+
+        default:
+            return ("Unknown system error");
+    }
+#endif
+}
+
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 4a3a38a..dc3fd38 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5322,6 +5322,15 @@ void slapi_ch_array_add( char ***array, char *string );
 int slapi_ch_array_utf8_inlist(char **array, char *string);
 
 /**
+ * Returns the error string of an ldap result code, but it can also handle
+ * library errors(negative result codes)
+ *
+ * \param result The result code
+ * \return The error text string of the result code
+ */
+char *slapi_err2string(int result);
+
+/**
  * Check if the server has started shutting down
  *
  * \return 1 if the server is shutting down


commit 07601165b5c062b385df00d1275c1cccca5593e9
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed May 30 13:30:44 2012 -0400

    Update the slapi-plugin documentation on new slapi functions, and added a slapi function for checking on shutdowns
    
    Fix Description:  removed the g_get_shutdown() functions from the plugins, and replaced them with the slapi version
    
    Reviewed by: Richm (Thanks!)
    (cherry picked from commit 4d564ef42db022a5102c9b6ae1bdd41a18c1dd7f)

diff --git a/ldap/servers/plugins/linkedattrs/fixup_task.c b/ldap/servers/plugins/linkedattrs/fixup_task.c
index b19d3ab..9fa7f6f 100644
--- a/ldap/servers/plugins/linkedattrs/fixup_task.c
+++ b/ldap/servers/plugins/linkedattrs/fixup_task.c
@@ -355,7 +355,7 @@ linked_attrs_add_backlinks_callback(Slapi_Entry *e, void *callback_data)
         int perform_update = 0;
         Slapi_DN *targetsdn = NULL;
 
-        if (g_get_shutdown()) {
+        if (slapi_is_shutting_down()) {
             rc = -1;
             goto done;
         }
diff --git a/ldap/servers/plugins/linkedattrs/linked_attrs.h b/ldap/servers/plugins/linkedattrs/linked_attrs.h
index 2eba62f..d0909ca 100644
--- a/ldap/servers/plugins/linkedattrs/linked_attrs.h
+++ b/ldap/servers/plugins/linkedattrs/linked_attrs.h
@@ -138,8 +138,6 @@ int linked_attrs_fixup_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
                            Slapi_Entry *eAfter, int *returncode,
                            char *returntext, void *arg);
 
-int g_get_shutdown();		/* declared in proto-slap.h */
-
 /*
  * misc
  */
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
index 8deed0f..a2fdbd9 100644
--- a/ldap/servers/plugins/memberof/memberof.c
+++ b/ldap/servers/plugins/memberof/memberof.c
@@ -1700,7 +1700,7 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
 	Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)callback_data)->groupvals;
 	int rc = 0;
 
-	if(g_get_shutdown()){
+	if(slapi_is_shutting_down()){
 		rc = -1;
 		goto bail;
 	}
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
index 36901e3..65398aa 100644
--- a/ldap/servers/plugins/memberof/memberof.h
+++ b/ldap/servers/plugins/memberof/memberof.h
@@ -96,6 +96,4 @@ void memberof_wlock_config();
 void memberof_unlock_config();
 int memberof_config_get_all_backends();
 
-int g_get_shutdown();		/* declared in proto-slap.h */
-
 #endif	/* _MEMBEROF_H_ */
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index eac76a8..08bf771 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -265,8 +265,6 @@ typedef struct cl5desc
 
 typedef void (*VFP)(void *);
 
-int g_get_shutdown();		/* declared in proto-slap.h */
-
 /***** Global Variables *****/
 static CL5Desc s_cl5Desc;
 
@@ -3472,7 +3470,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim)
 
 	entry.op = &op;
 
-	while ( !finished && !g_get_shutdown() )
+	while ( !finished && !slapi_is_shutting_down() )
 	{
 		it = NULL;
 		count = 0;
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index 6434dbd..ccaa29d 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -50,9 +50,6 @@
 #include "csnpl.h"
 #include "cl5_api.h"
 
-/* from proto-slap.h */
-int g_get_shutdown();
-
 #define RUV_SAVE_INTERVAL (30 * 1000) /* 30 seconds */
 #define START_UPDATE_DELAY 2 /* 2 second */
 
@@ -2506,7 +2503,7 @@ process_reap_entry (Slapi_Entry *entry, void *cb_data)
 	int rc = -1;
 
 	/* abort reaping if we've been told to stop or we're shutting down */
-	if (*tombstone_reap_stop || g_get_shutdown()) {
+	if (*tombstone_reap_stop || slapi_is_shutting_down()) {
 		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
 						"process_reap_entry: the tombstone reap process "
 						" has been stopped\n");
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 7d252ed..a5d608a 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -86,7 +86,6 @@ static struct berval *create_ruv_payload(char *value);
 static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
 static int replica_task_done(Replica *replica);
 static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
-int g_get_shutdown();
 
 /*
  * Note: internal add/modify/delete operations should not be run while
@@ -1325,7 +1324,7 @@ replica_cleanallruv_monitor_thread(void *arg)
 
 	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Waiting for all the replicas to get cleaned...\n");
 
-	while(!g_get_shutdown())
+	while(!slapi_is_shutting_down())
 	{
 		DS_Sleep(PR_SecondsToInterval(10));
 		found = 0;
diff --git a/ldap/servers/plugins/usn/usn_cleanup.c b/ldap/servers/plugins/usn/usn_cleanup.c
index 6f9410e..ab6362f 100644
--- a/ldap/servers/plugins/usn/usn_cleanup.c
+++ b/ldap/servers/plugins/usn/usn_cleanup.c
@@ -148,7 +148,7 @@ usn_cleanup_thread(void *arg)
         int opflags = OP_FLAG_TOMBSTONE_ENTRY;
 
         /* check for shutdown */
-        if(g_get_shutdown()){
+        if(slapi_is_shutting_down()){
             slapi_task_log_notice(task, "USN tombstone cleanup task aborted due to shutdown.");
             slapi_task_log_status(task, "USN tombstone cleanup task aborted due to shutdown.");
             slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 59561c7..3589f08 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -890,6 +890,11 @@ int g_get_shutdown()
     return slapd_shutdown;
 }
 
+int slapi_is_shutting_down()
+{
+	return slapd_shutdown;
+}
+
 
 static int cmd_shutdown;
 
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index fc0281f..4a3a38a 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5321,6 +5321,13 @@ void slapi_ch_array_add( char ***array, char *string );
  */
 int slapi_ch_array_utf8_inlist(char **array, char *string);
 
+/**
+ * Check if the server has started shutting down
+ *
+ * \return 1 if the server is shutting down
+ */
+int slapi_is_shutting_down();
+
 /*
  * checking routines for allocating and freeing memory
  */
@@ -6762,7 +6769,20 @@ int slapi_re_exec( Slapi_Regex *re_handle, const char *subject, time_t time_up )
  * \warning The regex handler should be released by slapi_re_free().
  */
 int slapi_re_subs( Slapi_Regex *re_handle, const char *subject, const char *src, char **dst, unsigned long dstlen );
-/* extension to handle search filters properly */
+/**
+ * Substitutes '&' or '\#' in the param src with the matched string.  If the 'src' is a search filter
+ * do not remove & if it is part of a compound filter.
+ *
+ * \param re_handle The regex handler returned from slapi_re_comp.
+ * \param subject A string checked against the compiled pattern.
+ * \param src A given string which could contain the substitution symbols.
+ * \param dst A pointer pointing to the memory which stores the output string.
+ * \param dstlen Size of the memory dst.
+ * \param filter Set to 1 if the src is a ldap search filter
+ * \return This function returns 1 if the substitution was successful.
+ * \return This function returns 0 if the substitution failed.
+ * \warning The regex handler should be released by slapi_re_free().
+ */
 int slapi_re_subs_ext( Slapi_Regex *re_handle, const char *subject, const char *src, char **dst, unsigned long dstlen, int filter );
 /**
  * Releases the regex handler which was returned from slapi_re_comp.


commit e11b3a5cc61786a5dc8aeb4cc20caa60ed7d9173
Author: Mark Reynolds <mreynolds at redhat.com>
Date:   Wed May 30 11:06:55 2012 -0400

    Ticket #369 - restore of replica ldif file on second master after deleting two records shows only 1 deletion
    
    Bug Description:  If you take a "db2ldif -r" on a consumer and later restore it "ldif2db"
                      any changes made on that consumer after the backup(db2ldif), will not be
                      replayed back to the consumer after it has been restored(ldif2db).
    
    Fix Description:  When we check if we can skip updates from the change log, check if the
                      consumer csn is "newer" than its current max csn.  If it is, then it
                      needs to be replayed back to itself.
    
    https://fedorahosted.org/389/ticket/369
    
    Reviewed by: Nathan & Rich (Thanks!)
    (cherry picked from commit a640ac21971fef404c690594c83a7f54c334fe90)

diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
index 327cb6f..5816837 100644
--- a/ldap/servers/plugins/replication/cl5_clcache.c
+++ b/ldap/servers/plugins/replication/cl5_clcache.c
@@ -664,13 +664,24 @@ clcache_skip_change ( CLC_Buffer *buf )
 		rid = csn_get_replicaid ( buf->buf_current_csn );
 
 		/*
-		 * Skip CSN that is originated from the consumer.
+		 * Skip CSN that is originated from the consumer,
+		 * unless the CSN is newer than the maxcsn.
 		 * If RID==65535, the CSN is originated from a
 		 * legacy consumer. In this case the supplier
 		 * and the consumer may have the same RID.
 		 */
-		if (rid == buf->buf_consumer_rid && rid != MAX_REPLICA_ID)
+		if (rid == buf->buf_consumer_rid && rid != MAX_REPLICA_ID){
+			CSN *cons_maxcsn = NULL;
+
+			ruv_get_max_csn(buf->buf_consumer_ruv, &cons_maxcsn);
+			if ( csn_compare ( buf->buf_current_csn, cons_maxcsn) > 0 ) {
+				/*
+				 *  The consumer must have been "restored" and needs this newer update.
+				 */
+				skip = 0;
+			}
 			break;
+		}
 
 		/* Skip helper entry (ENTRY_COUNT, PURGE_RUV and so on) */
 		if ( cl5HelperEntry ( NULL, buf->buf_current_csn ) == PR_TRUE ) {




More information about the 389-commits mailing list