]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
fix previous commit (ITS#5819)
[openldap] / servers / slapd / syncrepl.c
index 426d40cbdfaad852bd95bf02a713167299dfa611..a9f9cf66cc8ca86ff031b14efca36a15e7e59fd5 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2007 The OpenLDAP Foundation.
+ * Copyright 2003-2008 The OpenLDAP Foundation.
  * Portions Copyright 2003 by IBM Corporation.
  * Portions Copyright 2003 by Howard Chu, Symas Corporation.
  * All rights reserved.
@@ -63,7 +63,7 @@ typedef struct syncinfo_s {
        BackendDB               *si_wbe;
        struct re_s             *si_re;
        int                     si_rid;
-       char                    si_ridtxt[8];
+       char                    si_ridtxt[ STRLENOF("rid=999") + 1 ];
        slap_bindconf           si_bindconf;
        struct berval           si_base;
        struct berval           si_logbase;
@@ -93,18 +93,20 @@ typedef struct syncinfo_s {
        int                     si_tlimit;
        int                     si_refreshDelete;
        int                     si_refreshPresent;
+       int                     si_refreshDone;
        int                     si_syncdata;
        int                     si_logstate;
-       int                     si_conn_setup;
+       ber_int_t       si_msgid;
        Avlnode                 *si_presentlist;
        LDAP                    *si_ld;
+       Connection              *si_conn;
        LDAP_LIST_HEAD(np, nonpresent_entry)    si_nonpresentlist;
        ldap_pvt_thread_mutex_t si_mutex;
 } syncinfo_t;
 
 static int syncuuid_cmp( const void *, const void * );
-static void avl_ber_bvfree( void * );
-static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct berval * );
+static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
+static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
 static int syncrepl_message_to_op(
                                        syncinfo_t *, Operation *, LDAPMessage * );
 static int syncrepl_message_to_entry(
@@ -112,7 +114,8 @@ static int syncrepl_message_to_entry(
                                        Modifications **, Entry **, int );
 static int syncrepl_entry(
                                        syncinfo_t *, Operation*, Entry*,
-                                       Modifications**,int, struct berval* );
+                                       Modifications**,int, struct berval*,
+                                       struct berval *cookieCSN );
 static int syncrepl_updateCookie(
                                        syncinfo_t *, Operation *, struct berval *,
                                        struct sync_cookie * );
@@ -126,6 +129,26 @@ static int null_callback( Operation *, SlapReply * );
 
 static AttributeDescription *sync_descs[4];
 
+static const char *
+syncrepl_state2str( int state )
+{
+       switch ( state ) {
+       case LDAP_SYNC_PRESENT:
+               return "PRESENT";
+
+       case LDAP_SYNC_ADD:
+               return "ADD";
+
+       case LDAP_SYNC_MODIFY:
+               return "MODIFY";
+
+       case LDAP_SYNC_DELETE:
+               return "DELETE";
+       }
+
+       return "UNKNOWN";
+}
+
 static void
 init_syncrepl(syncinfo_t *si)
 {
@@ -320,7 +343,6 @@ ldap_sync_search(
        BerElementBuffer berbuf;
        BerElement *ber = (BerElement *)&berbuf;
        LDAPControl c[2], *ctrls[3];
-       ber_int_t       msgid;
        int rc;
        int rhint;
        char *base;
@@ -385,7 +407,7 @@ ldap_sync_search(
                        abs(si->si_type), rhint );
        }
 
-       if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == LBER_ERROR ) {
+       if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
                ber_free_buf( ber );
                return rc;
        }
@@ -405,11 +427,117 @@ ldap_sync_search(
        }
 
        rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
-               ctrls, NULL, NULL, si->si_slimit, &msgid );
+               ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
        ber_free_buf( ber );
        return rc;
 }
 
+static int
+check_syncprov(
+       Operation *op,
+       syncinfo_t *si )
+{
+       AttributeName at[2];
+       Attribute a = {0};
+       Entry e = {0};
+       SlapReply rs = {0};
+       int i, j, changed = 0;
+
+       /* Look for contextCSN from syncprov overlay. If
+        * there's no overlay, this will be a no-op. That means
+        * this is a pure consumer, so local changes will not be
+        * allowed, and all changes will already be reflected in
+        * the cookieState.
+        */
+       a.a_desc = slap_schema.si_ad_contextCSN;
+       e.e_attrs = &a;
+       e.e_name = op->o_bd->be_suffix[0];
+       e.e_nname = op->o_bd->be_nsuffix[0];
+       at[0].an_name = a.a_desc->ad_cname;
+       at[0].an_desc = a.a_desc;
+       BER_BVZERO( &at[1].an_name );
+       rs.sr_entry = &e;
+       rs.sr_flags = REP_ENTRY_MODIFIABLE;
+       rs.sr_attrs = at;
+       op->o_req_dn = e.e_name;
+       op->o_req_ndn = e.e_nname;
+
+       ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+       i = backend_operational( op, &rs );
+       if ( i == LDAP_SUCCESS && a.a_nvals ) {
+               int num = a.a_numvals;
+               /* check for differences */
+               if ( num != si->si_cookieState->cs_num ) {
+                       changed = 1;
+               } else {
+                       for ( i=0; i<num; i++ ) {
+                               if ( ber_bvcmp( &a.a_nvals[i],
+                                       &si->si_cookieState->cs_vals[i] )) {
+                                       changed = 1;
+                                       break;
+                               }
+                       }
+               }
+               if ( changed ) {
+                       ber_bvarray_free( si->si_cookieState->cs_vals );
+                       ch_free( si->si_cookieState->cs_sids );
+                       si->si_cookieState->cs_num = num;
+                       si->si_cookieState->cs_vals = a.a_nvals;
+                       si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
+                               num, NULL );
+                       si->si_cookieState->cs_age++;
+               } else {
+                       ber_bvarray_free( a.a_nvals );
+               }
+               ber_bvarray_free( a.a_vals );
+       }
+       /* See if the cookieState has changed due to anything outside
+        * this particular consumer. That includes other consumers in
+        * the same context, or local changes detected above.
+        */
+       if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
+               si->si_cookieState->cs_age ) {
+               if ( !si->si_syncCookie.numcsns ) {
+                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
+                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+                               si->si_cookieState->cs_vals, NULL );
+                       changed = 1;
+               } else {
+                       for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
+                               /* bogus, just dup everything */
+                               if ( si->si_syncCookie.sids[i] == -1 ) {
+                                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
+                                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+                                               si->si_cookieState->cs_vals, NULL );
+                                       changed = 1;
+                                       break;
+                               }
+                               for (j=0; j<si->si_cookieState->cs_num; j++) {
+                                       if ( si->si_syncCookie.sids[i] !=
+                                               si->si_cookieState->cs_sids[j] )
+                                               continue;
+                                       if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
+                                               &si->si_cookieState->cs_vals[j] ))
+                                               break;
+                                       ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
+                                               &si->si_cookieState->cs_vals[j] );
+                                       changed = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       if ( changed ) {
+               si->si_cookieAge = si->si_cookieState->cs_age;
+               ch_free( si->si_syncCookie.octet_str.bv_val );
+               slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
+                       si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
+                       si->si_syncCookie.sid );
+       }
+       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+       return changed;
+}
+
 static int
 do_syncrep1(
        Operation *op,
@@ -440,22 +568,32 @@ do_syncrep1(
                op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
        }
 #endif /* HAVE_TLS */
-       ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
+       {
+               ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
+                                                 to use sasl_ssf_t but currently uses ber_len_t */
+               ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf );
+               op->o_sasl_ssf = ssf;
+       }
        op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
                ?  op->o_sasl_ssf : op->o_tls_ssf;
 
        ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
 
+       rc = LDAP_DEREF_NEVER;  /* actually could allow DEREF_FINDING */
+       ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
+
+       si->si_syncCookie.rid = si->si_rid;
+
+       /* whenever there are multiple data sources possible, advertise sid */
+       si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
+               slap_serverID : -1;
+
        /* We've just started up, or the remote server hasn't sent us
         * any meaningful state.
         */
        if ( BER_BVISNULL( &si->si_syncCookie.octet_str ) ) {
                int i;
 
-               si->si_syncCookie.rid = si->si_rid;
-               si->si_syncCookie.sid = SLAP_SINGLE_SHADOW( si->si_be ) ? -1 :
-                       slap_serverID;
-
                LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
                        if ( si->si_rid == sc->rid ) {
                                cmdline_cookie_found = 1;
@@ -500,6 +638,7 @@ do_syncrep1(
                                if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
                                        si->si_cookieState->cs_vals, NULL )) {
                                        rc = LDAP_NO_MEMORY;
+                                       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
                                        goto done;
                                }
                                si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
@@ -515,100 +654,12 @@ do_syncrep1(
                        si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
                        si->si_syncCookie.sid );
        } else {
-               AttributeName at[2];
-               Attribute a = {0};
-               Entry e = {0};
-               SlapReply rs = {0};
-               int i, j, changed = 0;
-
-               /* Look for contextCSN from syncprov overlay. If
-                * there's no overlay, this will be a no-op. That means
-                * this is a pure consumer, so local changes will not be
-                * allowed, and all changes will already be reflected in
-                * the cookieState.
-                */
-               a.a_desc = slap_schema.si_ad_contextCSN;
-               e.e_attrs = &a;
-               e.e_name = si->si_wbe->be_suffix[0];
-               e.e_nname = si->si_wbe->be_nsuffix[0];
-               rs.sr_entry = &e;
-               rs.sr_flags = REP_ENTRY_MODIFIABLE;
-               at[0].an_name = a.a_desc->ad_cname;
-               at[0].an_desc = a.a_desc;
-               BER_BVZERO( &at[1].an_name );
-               op->o_req_dn = e.e_name;
-               op->o_req_ndn = e.e_nname;
-
-               ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
-               rc = backend_operational( op, &rs );
-               if ( rc == LDAP_SUCCESS && a.a_vals ) {
-                       int num;
-                       for (i=0; !BER_BVISNULL( &a.a_vals[i] ); i++) ;
-                       num = i;
-                       /* check for differences */
-                       if ( num != si->si_cookieState->cs_num ) {
-                               changed = 1;
-                       } else {
-                               for ( i=0; i<num; i++ ) {
-                                       if ( ber_bvcmp( &a.a_vals[i],
-                                               &si->si_cookieState->cs_vals[i] )) {
-                                               changed =1;
-                                               break;
-                                       }
-                               }
-                       }
-                       if ( changed ) {
-                               ber_bvarray_free( si->si_cookieState->cs_vals );
-                               ch_free( si->si_cookieState->cs_sids );
-                               si->si_cookieState->cs_num = num;
-                               si->si_cookieState->cs_vals = a.a_vals;
-                               si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_vals,
-                                       num, NULL );
-                               si->si_cookieState->cs_age++;
-                       } else {
-                               ber_bvarray_free( a.a_vals );
-                       }
-                       changed = 0;
-               }
-               /* See if the cookieState has changed due to anything outside
-                * this particular consumer. That includes other consumers in
-                * the same context, or local changes detected above.
-                */
-               if ( si->si_cookieState->cs_num > 1 && si->si_cookieAge !=
-                       si->si_cookieState->cs_age ) {
-
-                       for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
-                               /* bogus, just dup everything */
-                               if ( si->si_syncCookie.sids[i] == -1 ) {
-                                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
-                                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
-                                               si->si_cookieState->cs_vals, NULL );
-                                       changed = 1;
-                                       break;
-                               }
-                               for (j=0; j<si->si_cookieState->cs_num; j++) {
-                                       if ( si->si_syncCookie.sids[i] !=
-                                               si->si_cookieState->cs_sids[j] )
-                                               continue;
-                                       if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
-                                               &si->si_cookieState->cs_vals[j] ))
-                                               break;
-                                       ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
-                                               &si->si_cookieState->cs_vals[j] );
-                                       changed = 1;
-                                       break;
-                               }
-                       }
-                       if ( changed ) {
-                               ch_free( si->si_syncCookie.octet_str.bv_val );
-                               slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
-                                       si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
-                                       SLAP_SINGLE_SHADOW( si->si_be ) ? -1 : slap_serverID );
-                       }
-               }
-               ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+               /* Look for contextCSN from syncprov overlay. */
+               check_syncprov( op, si );
        }
 
+       si->si_refreshDone = 0;
+
        rc = ldap_sync_search( si, op->o_tmpmemctx );
 
        if( rc != LDAP_SUCCESS ) {
@@ -641,24 +692,31 @@ compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
                return -1;
        }
 
-       for (i=0; !BER_BVISNULL( &sc1->ctxcsn[i] ); i++) {
-               for (j=0; !BER_BVISNULL( &sc2->ctxcsn[j] ); j++) {
+       for (j=0; j<sc2->numcsns; j++) {
+               for (i=0; i<sc1->numcsns; i++) {
                        if ( sc1->sids[i] != sc2->sids[j] )
                                continue;
                        value_match( &match, slap_schema.si_ad_entryCSN,
                                slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
                                SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
-                               &sc1->ctxcsn[i], &sc2->ctxcsn[i], &text );
+                               &sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
                        if ( match < 0 ) {
                                *which = j;
                                return match;
                        }
                        break;
                }
+               if ( i == sc1->numcsns ) {
+                       /* sc2 has a sid sc1 lacks */
+                       *which = j;
+                       return -1;
+               }
        }
        return match;
 }
 
+#define        SYNC_PAUSED     -3
+
 static int
 do_syncrep2(
        Operation *op,
@@ -670,7 +728,6 @@ do_syncrep2(
        BerElementBuffer berbuf;
        BerElement      *ber = (BerElement *)&berbuf;
 
-       LDAPMessage     *res = NULL;
        LDAPMessage     *msg = NULL;
 
        char            *retoid = NULL;
@@ -697,7 +754,6 @@ do_syncrep2(
        struct timeval tout = { 0, 0 };
 
        int             refreshDeletes = 0;
-       int             refreshDone = 1;
        BerVarray syncUUIDs = NULL;
        ber_tag_t si_tag;
 
@@ -721,133 +777,334 @@ do_syncrep2(
                tout_p = NULL;
        }
 
-       while ( ( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE,
-               tout_p, &res ) ) > 0 )
+       while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
+               tout_p, &msg ) ) > 0 )
        {
                if ( slapd_shutdown ) {
                        rc = -2;
                        goto done;
                }
-               for( msg = ldap_first_message( si->si_ld, res );
-                       msg != NULL;
-                       msg = ldap_next_message( si->si_ld, msg ) )
-               {
-                       if ( slapd_shutdown ) {
-                               rc = -2;
-                               goto done;
-                       }
-                       switch( ldap_msgtype( msg ) ) {
-                       case LDAP_RES_SEARCH_ENTRY:
-                               ldap_get_entry_controls( si->si_ld, msg, &rctrls );
-                               /* we can't work without the control */
-                               rctrlp = NULL;
-                               if ( rctrls ) {
-                                       /* NOTE: make sure we use the right one;
-                                        * a better approach would be to run thru
-                                        * the whole list and take care of all */
-                                       rctrlp = ldap_find_control( LDAP_CONTROL_SYNC_STATE, rctrls );
-                               }
-                               if ( rctrlp == NULL ) {
+               switch( ldap_msgtype( msg ) ) {
+               case LDAP_RES_SEARCH_ENTRY:
+                       ldap_get_entry_controls( si->si_ld, msg, &rctrls );
+                       /* we can't work without the control */
+                       rctrlp = NULL;
+                       if ( rctrls ) {
+                               LDAPControl **next;
+                               /* NOTE: make sure we use the right one;
+                                * a better approach would be to run thru
+                                * the whole list and take care of all */
+                               rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
+                               if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
+                               {
                                        Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                               "got search entry without "
+                                               "got search entry with multiple "
                                                "Sync State control\n", si->si_ridtxt, 0, 0 );
                                        rc = -1;
                                        goto done;
                                }
-                               ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
-                               ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
-                               /* FIXME: what if syncUUID is NULL or empty?
-                                * (happens with back-sql...) */
-                               if ( BER_BVISEMPTY( &syncUUID ) ) {
-                                       Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                               "got empty syncUUID\n", si->si_ridtxt, 0, 0 );
-                                       ldap_controls_free( rctrls );
-                                       rc = -1;
-                                       goto done;
+                       }
+                       if ( rctrlp == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+                                       "got search entry without "
+                                       "Sync State control\n", si->si_ridtxt, 0, 0 );
+                               rc = -1;
+                               goto done;
+                       }
+                       ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+                       ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
+                       /* FIXME: what if syncUUID is NULL or empty?
+                        * (happens with back-sql...) */
+                       if ( BER_BVISEMPTY( &syncUUID ) ) {
+                               Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+                                       "got empty syncUUID with LDAP_SYNC_%s\n",
+                                       si->si_ridtxt,
+                                       syncrepl_state2str( syncstate ), 0 );
+                               ldap_controls_free( rctrls );
+                               rc = -1;
+                               goto done;
+                       }
+                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
+                               ber_scanf( ber, /*"{"*/ "m}", &cookie );
+
+                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+
+                               if ( !BER_BVISNULL( &cookie ) ) {
+                                       ch_free( syncCookie.octet_str.bv_val );
+                                       ber_dupbv( &syncCookie.octet_str, &cookie );
+                               }
+                               if ( !BER_BVISNULL( &syncCookie.octet_str ) )
+                               {
+                                       slap_parse_sync_cookie( &syncCookie, NULL );
+                                       if ( syncCookie.ctxcsn ) {
+                                               int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
+                                               for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+                                                       if ( si->si_cookieState->cs_sids[i] == sid && 
+                                                               ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+                                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
+                                                                       si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
+                                                               ldap_controls_free( rctrls );
+                                                               rc = 0;
+                                                               goto done;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       rc = 0;
+                       if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
+                               modlist = NULL;
+                               if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
+                                       syncCookie.ctxcsn )
+                               {
+                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+                               } else switch ( rc ) {
+                                       case LDAP_ALREADY_EXISTS:
+                                       case LDAP_NO_SUCH_OBJECT:
+                                       case LDAP_NO_SUCH_ATTRIBUTE:
+                                       case LDAP_TYPE_OR_VALUE_EXISTS:
+                                               rc = LDAP_SYNC_REFRESH_REQUIRED;
+                                               si->si_logstate = SYNCLOG_FALLBACK;
+                                               ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
+                               &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+                       {
+                               if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
+                                       syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
+                                       syncCookie.ctxcsn )
+                               {
+                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+                               }
+                       }
+                       ldap_controls_free( rctrls );
+                       if ( modlist ) {
+                               slap_mods_free( modlist, 1 );
+                       }
+                       if ( rc )
+                               goto done;
+                       break;
+
+               case LDAP_RES_SEARCH_REFERENCE:
+                       Debug( LDAP_DEBUG_ANY,
+                               "do_syncrep2: %s reference received error\n",
+                               si->si_ridtxt, 0, 0 );
+                       break;
+
+               case LDAP_RES_SEARCH_RESULT:
+                       Debug( LDAP_DEBUG_SYNC,
+                               "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
+                               si->si_ridtxt, 0, 0 );
+                       ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
+                               &rctrls, 0 );
+#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
+                       if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
+                               /* map old result code to registered code */
+                               err = LDAP_SYNC_REFRESH_REQUIRED;
+                       }
+#endif
+                       if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
+                               if ( si->si_logstate == SYNCLOG_LOGGING ) {
+                                       si->si_logstate = SYNCLOG_FALLBACK;
                                }
+                               rc = err;
+                               goto done;
+                       }
+                       if ( err ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                       "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
+                                       si->si_ridtxt, err, ldap_err2string( err ) );
+                       }
+                       if ( rctrls ) {
+                               rctrlp = *rctrls;
+                               ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+
+                               ber_scanf( ber, "{" /*"}"*/);
                                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
-                                       ber_scanf( ber, /*"{"*/ "m}", &cookie );
+                                       ber_scanf( ber, "m", &cookie );
+
+                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+                                               BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+
                                        if ( !BER_BVISNULL( &cookie ) ) {
                                                ch_free( syncCookie.octet_str.bv_val );
-                                               ber_dupbv( &syncCookie.octet_str, &cookie );
+                                               ber_dupbv( &syncCookie.octet_str, &cookie);
                                        }
                                        if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                        {
                                                slap_parse_sync_cookie( &syncCookie, NULL );
                                        }
                                }
-                               rc = 0;
-                               if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
-                                       modlist = NULL;
-                                       if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
-                                               syncCookie.ctxcsn )
-                                       {
-                                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                                       }
-                               } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
-                                       &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+                               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
                                {
-                                       if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
-                                               syncstate, &syncUUID ) ) == LDAP_SUCCESS &&
-                                               syncCookie.ctxcsn )
-                                       {
-                                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                                       }
+                                       ber_scanf( ber, "b", &refreshDeletes );
                                }
+                               ber_scanf( ber, /*"{"*/ "}" );
+                       }
+                       if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+                               slap_sync_cookie_free( &syncCookie_req, 0 );
+                               slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+                       }
+                       if ( !syncCookie.ctxcsn ) {
+                               match = 1;
+                       } else if ( !syncCookie_req.ctxcsn ) {
+                               match = -1;
+                               m = 0;
+                       } else {
+                               match = compare_csns( &syncCookie_req, &syncCookie, &m );
+                       }
+                       if ( rctrls ) {
                                ldap_controls_free( rctrls );
-                               if ( modlist ) {
-                                       slap_mods_free( modlist, 1 );
+                       }
+                       if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
+                               /* FIXME : different error behaviors according to
+                                *      1) err code : LDAP_BUSY ...
+                                *      2) on err policy : stop service, stop sync, retry
+                                */
+                               if ( refreshDeletes == 0 && match < 0 &&
+                                       err == LDAP_SUCCESS &&
+                                       syncCookie_req.numcsns == syncCookie.numcsns )
+                               {
+                                       syncrepl_del_nonpresent( op, si, NULL,
+                                               &syncCookie, m );
+                               } else {
+                                       avl_free( si->si_presentlist, ch_free );
+                                       si->si_presentlist = NULL;
                                }
-                               if ( rc )
-                                       goto done;
-                               break;
-
-                       case LDAP_RES_SEARCH_REFERENCE:
-                               Debug( LDAP_DEBUG_ANY,
-                                       "do_syncrep2: %s reference received error\n",
-                                       si->si_ridtxt, 0, 0 );
-                               break;
+                       }
+                       if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
+                       {
+                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+                       }
+                       if ( err == LDAP_SUCCESS
+                               && si->si_logstate == SYNCLOG_FALLBACK ) {
+                               si->si_logstate = SYNCLOG_LOGGING;
+                               rc = LDAP_SYNC_REFRESH_REQUIRED;
+                       } else {
+                               rc = -2;
+                       }
+                       goto done;
+                       break;
 
-                       case LDAP_RES_SEARCH_RESULT:
-                               Debug( LDAP_DEBUG_SYNC,
-                                       "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
-                                       si->si_ridtxt, 0, 0 );
-                               ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
-                                       &rctrls, 0 );
-#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
-                               if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
-                                       /* map old result code to registered code */
-                                       err = LDAP_SYNC_REFRESH_REQUIRED;
-                               }
-#endif
-                               if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
-                                       if ( si->si_logstate == SYNCLOG_LOGGING ) {
-                                               si->si_logstate = SYNCLOG_FALLBACK;
+               case LDAP_RES_INTERMEDIATE:
+                       rc = ldap_parse_intermediate( si->si_ld, msg,
+                               &retoid, &retdata, NULL, 0 );
+                       if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
+                               ber_init2( ber, retdata, LBER_USE_DER );
+
+                               switch ( si_tag = ber_peek_tag( ber, &len ) ) {
+                               ber_tag_t tag;
+                               case LDAP_TAG_SYNC_NEW_COOKIE:
+                                       Debug( LDAP_DEBUG_SYNC,
+                                               "do_syncrep2: %s %s - %s\n", 
+                                               si->si_ridtxt,
+                                               "LDAP_RES_INTERMEDIATE", 
+                                               "NEW_COOKIE" );
+                                       ber_scanf( ber, "tm", &tag, &cookie );
+                                       break;
+                               case LDAP_TAG_SYNC_REFRESH_DELETE:
+                               case LDAP_TAG_SYNC_REFRESH_PRESENT:
+                                       Debug( LDAP_DEBUG_SYNC,
+                                               "do_syncrep2: %s %s - %s\n", 
+                                               si->si_ridtxt,
+                                               "LDAP_RES_INTERMEDIATE", 
+                                               si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
+                                               "REFRESH_PRESENT" : "REFRESH_DELETE" );
+                                       if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
+                                               si->si_refreshDelete = 1;
+                                       } else {
+                                               si->si_refreshPresent = 1;
                                        }
-                                       rc = err;
-                                       goto done;
-                               }
-                               if ( rctrls ) {
-                                       rctrlp = *rctrls;
-                                       ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+                                       ber_scanf( ber, "t{" /*"}"*/, &tag );
+                                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
+                                       {
+                                               ber_scanf( ber, "m", &cookie );
 
-                                       ber_scanf( ber, "{" /*"}"*/);
-                                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
+                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+
+                                               if ( !BER_BVISNULL( &cookie ) ) {
+                                                       ch_free( syncCookie.octet_str.bv_val );
+                                                       ber_dupbv( &syncCookie.octet_str, &cookie );
+                                               }
+                                               if ( !BER_BVISNULL( &syncCookie.octet_str ) )
+                                               {
+                                                       slap_parse_sync_cookie( &syncCookie, NULL );
+                                               }
+                                       }
+                                       /* Defaults to TRUE */
+                                       if ( ber_peek_tag( ber, &len ) ==
+                                               LDAP_TAG_REFRESHDONE )
+                                       {
+                                               ber_scanf( ber, "b", &si->si_refreshDone );
+                                       } else
+                                       {
+                                               si->si_refreshDone = 1;
+                                       }
+                                       ber_scanf( ber, /*"{"*/ "}" );
+                                       break;
+                               case LDAP_TAG_SYNC_ID_SET:
+                                       Debug( LDAP_DEBUG_SYNC,
+                                               "do_syncrep2: %s %s - %s\n", 
+                                               si->si_ridtxt,
+                                               "LDAP_RES_INTERMEDIATE", 
+                                               "SYNC_ID_SET" );
+                                       ber_scanf( ber, "t{" /*"}"*/, &tag );
+                                       if ( ber_peek_tag( ber, &len ) ==
+                                               LDAP_TAG_SYNC_COOKIE )
+                                       {
                                                ber_scanf( ber, "m", &cookie );
+
+                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+
                                                if ( !BER_BVISNULL( &cookie ) ) {
                                                        ch_free( syncCookie.octet_str.bv_val );
-                                                       ber_dupbv( &syncCookie.octet_str, &cookie);
+                                                       ber_dupbv( &syncCookie.octet_str, &cookie );
                                                }
                                                if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                                {
                                                        slap_parse_sync_cookie( &syncCookie, NULL );
+                                                       compare_csns( &syncCookie_req, &syncCookie, &m );
                                                }
                                        }
-                                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
+                                       if ( ber_peek_tag( ber, &len ) ==
+                                               LDAP_TAG_REFRESHDELETES )
                                        {
                                                ber_scanf( ber, "b", &refreshDeletes );
                                        }
+                                       ber_scanf( ber, "[W]", &syncUUIDs );
                                        ber_scanf( ber, /*"{"*/ "}" );
+                                       if ( refreshDeletes ) {
+                                               syncrepl_del_nonpresent( op, si, syncUUIDs,
+                                                       &syncCookie, m );
+                                               ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
+                                       } else {
+                                               int i;
+                                               for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
+                                                       (void)avl_presentlist_insert( si, &syncUUIDs[i] );
+                                                       slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+                                               }
+                                               slap_sl_free( syncUUIDs, op->o_tmpmemctx );
+                                       }
+                                       slap_sync_cookie_free( &syncCookie, 0 );
+                                       break;
+                               default:
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
+                                               si->si_ridtxt, (long) si_tag, 0 );
+                                       ldap_memfree( retoid );
+                                       ber_bvfree( retdata );
+                                       continue;
+                               }
+
+                               if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+                                       slap_sync_cookie_free( &syncCookie_req, 0 );
+                                       slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
                                }
                                if ( !syncCookie.ctxcsn ) {
                                        match = 1;
@@ -857,194 +1114,54 @@ do_syncrep2(
                                } else {
                                        match = compare_csns( &syncCookie_req, &syncCookie, &m );
                                }
-                               if ( rctrls ) {
-                                       ldap_controls_free( rctrls );
-                               }
-                               if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
-                                       /* FIXME : different error behaviors according to
-                                        *      1) err code : LDAP_BUSY ...
-                                        *      2) on err policy : stop service, stop sync, retry
-                                        */
-                                       if ( refreshDeletes == 0 && match < 0 &&
-                                               err == LDAP_SUCCESS )
-                                       {
-                                               syncrepl_del_nonpresent( op, si, NULL,
-                                                       &syncCookie.ctxcsn[m] );
-                                       } else {
-                                               avl_free( si->si_presentlist, avl_ber_bvfree );
-                                               si->si_presentlist = NULL;
-                                       }
-                               }
-                               if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
-                               {
-                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                               }
-                               if ( err == LDAP_SUCCESS
-                                       && si->si_logstate == SYNCLOG_FALLBACK ) {
-                                       si->si_logstate = SYNCLOG_LOGGING;
-                                       rc = LDAP_SYNC_REFRESH_REQUIRED;
-                               } else {
-                                       rc = -2;
-                               }
-                               goto done;
-                               break;
 
-                       case LDAP_RES_INTERMEDIATE:
-                               rc = ldap_parse_intermediate( si->si_ld, msg,
-                                       &retoid, &retdata, NULL, 0 );
-                               if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
-                                       ber_init2( ber, retdata, LBER_USE_DER );
-
-                                       switch ( si_tag = ber_peek_tag( ber, &len ) ) {
-                                       ber_tag_t tag;
-                                       case LDAP_TAG_SYNC_NEW_COOKIE:
-                                               Debug( LDAP_DEBUG_SYNC,
-                                                       "do_syncrep2: %s %s - %s\n", 
-                                                       si->si_ridtxt,
-                                                       "LDAP_RES_INTERMEDIATE", 
-                                                       "NEW_COOKIE" );
-                                               ber_scanf( ber, "tm", &tag, &cookie );
-                                               break;
-                                       case LDAP_TAG_SYNC_REFRESH_DELETE:
-                                       case LDAP_TAG_SYNC_REFRESH_PRESENT:
-                                               Debug( LDAP_DEBUG_SYNC,
-                                                       "do_syncrep2: %s %s - %s\n", 
-                                                       si->si_ridtxt,
-                                                       "LDAP_RES_INTERMEDIATE", 
-                                                       si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
-                                                       "REFRESH_PRESENT" : "REFRESH_DELETE" );
-                                               if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
-                                                       si->si_refreshDelete = 1;
-                                               } else {
-                                                       si->si_refreshPresent = 1;
-                                               }
-                                               ber_scanf( ber, "t{" /*"}"*/, &tag );
-                                               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
-                                               {
-                                                       ber_scanf( ber, "m", &cookie );
-                                                       if ( !BER_BVISNULL( &cookie ) ) {
-                                                               ch_free( syncCookie.octet_str.bv_val );
-                                                               ber_dupbv( &syncCookie.octet_str, &cookie );
-                                                       }
-                                                       if ( !BER_BVISNULL( &syncCookie.octet_str ) )
-                                                       {
-                                                               slap_parse_sync_cookie( &syncCookie, NULL );
-                                                       }
-                                               }
-                                               if ( ber_peek_tag( ber, &len ) ==
-                                                       LDAP_TAG_REFRESHDONE )
-                                               {
-                                                       ber_scanf( ber, "b", &refreshDone );
-                                               }
-                                               ber_scanf( ber, /*"{"*/ "}" );
-                                               break;
-                                       case LDAP_TAG_SYNC_ID_SET:
-                                               Debug( LDAP_DEBUG_SYNC,
-                                                       "do_syncrep2: %s %s - %s\n", 
-                                                       si->si_ridtxt,
-                                                       "LDAP_RES_INTERMEDIATE", 
-                                                       "SYNC_ID_SET" );
-                                               ber_scanf( ber, "t{" /*"}"*/, &tag );
-                                               if ( ber_peek_tag( ber, &len ) ==
-                                                       LDAP_TAG_SYNC_COOKIE )
-                                               {
-                                                       ber_scanf( ber, "m", &cookie );
-                                                       if ( !BER_BVISNULL( &cookie ) ) {
-                                                               ch_free( syncCookie.octet_str.bv_val );
-                                                               ber_dupbv( &syncCookie.octet_str, &cookie );
-                                                       }
-                                                       if ( !BER_BVISNULL( &syncCookie.octet_str ) )
-                                                       {
-                                                               slap_parse_sync_cookie( &syncCookie, NULL );
-                                                               compare_csns( &syncCookie_req, &syncCookie, &m );
-                                                       }
-                                               }
-                                               if ( ber_peek_tag( ber, &len ) ==
-                                                       LDAP_TAG_REFRESHDELETES )
-                                               {
-                                                       ber_scanf( ber, "b", &refreshDeletes );
-                                               }
-                                               ber_scanf( ber, "[W]", &syncUUIDs );
-                                               ber_scanf( ber, /*"{"*/ "}" );
-                                               if ( refreshDeletes ) {
-                                                       syncrepl_del_nonpresent( op, si, syncUUIDs,
-                                                               &syncCookie.ctxcsn[m] );
-                                                       ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
-                                               } else {
-                                                       int i;
-                                                       for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
-                                                               struct berval *syncuuid_bv;
-                                                               syncuuid_bv = ber_dupbv( NULL, &syncUUIDs[i] );
-                                                               slap_sl_free( syncUUIDs[i].bv_val,op->o_tmpmemctx );
-                                                               if ( avl_insert( &si->si_presentlist,
-                                                                       (caddr_t) syncuuid_bv,
-                                                                       syncuuid_cmp, avl_dup_error ) )
-                                                               {
-                                                                       ber_bvfree( syncuuid_bv );
-                                                               }
-                                                       }
-                                                       slap_sl_free( syncUUIDs, op->o_tmpmemctx );
-                                               }
-                                               slap_sync_cookie_free( &syncCookie, 0 );
-                                               break;
-                                       default:
-                                               Debug( LDAP_DEBUG_ANY,
-                                                       "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
-                                                       si->si_ridtxt, (long) si_tag, 0 );
-                                               ldap_memfree( retoid );
-                                               ber_bvfree( retdata );
-                                               continue;
+                               if ( match < 0 ) {
+                                       if ( si->si_refreshPresent == 1 &&
+                                               syncCookie_req.numcsns == syncCookie.numcsns ) {
+                                               syncrepl_del_nonpresent( op, si, NULL,
+                                                       &syncCookie, m );
                                        }
 
-                                       if ( !syncCookie.ctxcsn ) {
-                                               match = 1;
-                                       } else if ( !syncCookie_req.ctxcsn ) {
-                                               match = -1;
-                                               m = 0;
-                                       } else {
-                                               match = compare_csns( &syncCookie_req, &syncCookie, &m );
+                                       if ( syncCookie.ctxcsn )
+                                       {
+                                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
                                        }
+                               } 
 
-                                       if ( match < 0 ) {
-                                               if ( si->si_refreshPresent == 1 ) {
-                                                       syncrepl_del_nonpresent( op, si, NULL,
-                                                               &syncCookie.ctxcsn[m] );
-                                               }
-
-                                               if ( syncCookie.ctxcsn )
-                                               {
-                                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
-                                               }
-                                       } 
-
-                                       ldap_memfree( retoid );
-                                       ber_bvfree( retdata );
-                                       break;
-
-                               } else {
-                                       Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                               "unknown intermediate response (%d)\n",
-                                               si->si_ridtxt, rc, 0 );
-                                       ldap_memfree( retoid );
-                                       ber_bvfree( retdata );
-                                       break;
-                               }
+                               ldap_memfree( retoid );
+                               ber_bvfree( retdata );
                                break;
 
-                       default:
+                       } else {
                                Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                       "unknown message\n", si->si_ridtxt, 0, 0 );
+                                       "unknown intermediate response (%d)\n",
+                                       si->si_ridtxt, rc, 0 );
+                               ldap_memfree( retoid );
+                               ber_bvfree( retdata );
                                break;
-
-                       }
-                       if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
-                               slap_sync_cookie_free( &syncCookie_req, 0 );
-                               slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
-                               slap_sync_cookie_free( &syncCookie, 0 );
                        }
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+                               "unknown message (0x%02lx)\n",
+                               si->si_ridtxt,
+                               (unsigned long)ldap_msgtype( msg ), 0 );
+                       break;
+
+               }
+               if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
+                       slap_sync_cookie_free( &syncCookie_req, 0 );
+                       slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
+                       slap_sync_cookie_free( &syncCookie, 0 );
+               }
+               ldap_msgfree( msg );
+               msg = NULL;
+               if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
+                       slap_sync_cookie_free( &syncCookie, 0 );
+                       slap_sync_cookie_free( &syncCookie_req, 0 );
+                       return SYNC_PAUSED;
                }
-               ldap_msgfree( res );
-               res = NULL;
        }
 
        if ( rc == -1 ) {
@@ -1062,14 +1179,12 @@ done:
        slap_sync_cookie_free( &syncCookie, 0 );
        slap_sync_cookie_free( &syncCookie_req, 0 );
 
-       if ( res ) ldap_msgfree( res );
+       if ( msg ) ldap_msgfree( msg );
 
        if ( rc && rc != LDAP_SYNC_REFRESH_REQUIRED && si->si_ld ) {
-               if ( si->si_conn_setup ) {
-                       ber_socket_t s;
-                       ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
-                       connection_client_stop( s );
-                       si->si_conn_setup = 0;
+               if ( si->si_conn ) {
+                       connection_client_stop( si->si_conn );
+                       si->si_conn = NULL;
                }
                ldap_unbind_ext( si->si_ld, NULL, NULL );
                si->si_ld = NULL;
@@ -1099,6 +1214,7 @@ do_syncrepl(
        if ( si == NULL )
                return NULL;
 
+       /* There will never be more than one instance active */
        ldap_pvt_thread_mutex_lock( &si->si_mutex );
 
        switch( abs( si->si_type ) ) {
@@ -1112,10 +1228,9 @@ do_syncrepl(
 
        if ( slapd_shutdown ) {
                if ( si->si_ld ) {
-                       if ( si->si_conn_setup ) {
-                               ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
-                               connection_client_stop( s );
-                               si->si_conn_setup = 0;
+                       if ( si->si_conn ) {
+                               connection_client_stop( si->si_conn );
+                               si->si_conn = NULL;
                        }
                        ldap_unbind_ext( si->si_ld, NULL, NULL );
                        si->si_ld = NULL;
@@ -1132,25 +1247,45 @@ do_syncrepl(
        op->o_tmpmfuncs = &ch_mfuncs;
 
        op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
-       op->o_bd = be = si->si_be;
-       op->o_dn = op->o_bd->be_rootdn;
-       op->o_ndn = op->o_bd->be_rootndn;
-       if ( !si->si_schemachecking )
-               op->o_no_schema_check = 1;
-
-       /* If we're glued, send writes through the glue parent */
+       be = si->si_be;
+
+       /* Coordinate contextCSN updates with any syncprov overlays
+        * in use. This may be complicated by the use of the glue
+        * overlay.
+        *
+        * Typically there is a single syncprov mastering the entire
+        * glued tree. In that case, our contextCSN updates should
+        * go to the master DB. But if there is no syncprov on the
+        * master DB, then nothing special is needed here.
+        *
+        * Alternatively, there may be individual syncprov overlays
+        * on each glued branch. In that case, each syncprov only
+        * knows about changes within its own branch. And so our
+        * contextCSN updates should only go to the local DB.
+        */
        if ( !si->si_wbe ) {
-               if ( SLAP_GLUE_SUBORDINATE( be )) {
-                       si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+               if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
+                       BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
+                       if ( overlay_is_inst( top_be, "syncprov" ))
+                               si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+                       else
+                               si->si_wbe = be;
                } else {
                        si->si_wbe = be;
                }
        }
+       if ( !si->si_schemachecking )
+               op->o_no_schema_check = 1;
 
        /* Establish session, do search */
        if ( !si->si_ld ) {
                si->si_refreshDelete = 0;
                si->si_refreshPresent = 0;
+
+               /* use main DB when retrieving contextCSN */
+               op->o_bd = si->si_wbe;
+               op->o_dn = op->o_bd->be_rootdn;
+               op->o_ndn = op->o_bd->be_rootndn;
                rc = do_syncrep1( op, si );
        }
 
@@ -1159,6 +1294,10 @@ reload:
        if ( rc == LDAP_SUCCESS ) {
                ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
 
+               /* use current DB */
+               op->o_bd = be;
+               op->o_dn = op->o_bd->be_rootdn;
+               op->o_ndn = op->o_bd->be_rootndn;
                rc = do_syncrep2( op, si );
                if ( rc == LDAP_SYNC_REFRESH_REQUIRED ) {
                        rc = ldap_sync_search( si, op->o_tmpmemctx );
@@ -1167,36 +1306,37 @@ reload:
 
                /* We got deleted while running on cn=config */
                if ( !si->si_ctype ) {
-                       if ( si->si_conn_setup )
+                       if ( si->si_conn )
                                dostop = 1;
                        rc = -1;
                }
 
-               if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
-                       /* If we succeeded, enable the connection for further listening.
-                        * If we failed, tear down the connection and reschedule.
-                        */
-                       if ( rc == LDAP_SUCCESS ) {
-                               if ( si->si_conn_setup ) {
-                                       connection_client_enable( s );
-                               } else {
-                                       rc = connection_client_setup( s, do_syncrepl, arg );
-                                       if ( rc == 0 )
-                                               si->si_conn_setup = 1;
-                               } 
-                       } else if ( si->si_conn_setup ) {
-                               dostop = 1;
+               if ( rc != SYNC_PAUSED ) {
+                       if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+                               /* If we succeeded, enable the connection for further listening.
+                                * If we failed, tear down the connection and reschedule.
+                                */
+                               if ( rc == LDAP_SUCCESS ) {
+                                       if ( si->si_conn ) {
+                                               connection_client_enable( si->si_conn );
+                                       } else {
+                                               si->si_conn = connection_client_setup( s, do_syncrepl, arg );
+                                       } 
+                               } else if ( si->si_conn ) {
+                                       dostop = 1;
+                               }
+                       } else {
+                               if ( rc == -2 ) rc = 0;
                        }
-               } else {
-                       if ( rc == -2 ) rc = 0;
                }
        }
 
-       /* At this point, we have 4 cases:
+       /* At this point, we have 5 cases:
         * 1) for any hard failure, give up and remove this task
-        * 2) for ServerDown, reschedule this task to run
-        * 3) for Refresh and Success, reschedule to run
-        * 4) for Persist and Success, reschedule to defer
+        * 2) for ServerDown, reschedule this task to run later
+        * 3) for threadpool pause, reschedule to run immediately
+        * 4) for Refresh and Success, reschedule to run
+        * 5) for Persist and Success, reschedule to defer
         */
        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
 
@@ -1205,10 +1345,16 @@ reload:
        }
 
        if ( dostop ) {
-               connection_client_stop( s );
+               connection_client_stop( si->si_conn );
+               si->si_conn = NULL;
        }
 
-       if ( rc == LDAP_SUCCESS ) {
+       if ( rc == SYNC_PAUSED ) {
+               rtask->interval.tv_sec = 0;
+               ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
+               rtask->interval.tv_sec = si->si_interval;
+               rc = 0;
+       } else if ( rc == LDAP_SUCCESS ) {
                if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
                        defer = 0;
                }
@@ -1246,16 +1392,16 @@ reload:
        if ( rc ) {
                if ( fail == RETRYNUM_TAIL ) {
                        Debug( LDAP_DEBUG_ANY,
-                               "do_syncrepl: rid %03d quitting\n",
-                               si->si_rid, 0, 0 );
+                               "do_syncrepl: %s quitting\n",
+                               si->si_ridtxt, 0, 0 );
                } else if ( fail > 0 ) {
                        Debug( LDAP_DEBUG_ANY,
-                               "do_syncrepl: rid %03d retrying (%d retries left)\n",
-                               si->si_rid, fail, 0 );
+                               "do_syncrepl: %s retrying (%d retries left)\n",
+                               si->si_ridtxt, fail, 0 );
                } else {
                        Debug( LDAP_DEBUG_ANY,
-                               "do_syncrepl: rid %03d retrying\n",
-                               si->si_rid, 0, 0 );
+                               "do_syncrepl: %s retrying\n",
+                               si->si_ridtxt, 0, 0 );
                }
        }
 
@@ -1350,6 +1496,7 @@ syncrepl_accesslog_mods(
                        mod->sml_type = ad->ad_cname;
                        mod->sml_values = NULL;
                        mod->sml_nvalues = NULL;
+                       mod->sml_numvals = 0;
 
                        *modtail = mod;
                        modtail = &mod->sml_next;
@@ -1359,6 +1506,7 @@ syncrepl_accesslog_mods(
                        bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
                        ber_dupbv( &bv2, &bv );
                        ber_bvarray_add( &mod->sml_values, &bv2 );
+                       mod->sml_numvals++;
                }
        }
        return modlist;
@@ -1691,6 +1839,7 @@ syncrepl_message_to_entry(
                mod->sml_type = tmp.sml_type;
                mod->sml_values = tmp.sml_values;
                mod->sml_nvalues = NULL;
+               mod->sml_numvals = 0;   /* slap_mods_check will set this */
 
                *modtail = mod;
                modtail = &mod->sml_next;
@@ -1783,11 +1932,33 @@ typedef struct dninfo {
        struct berval dn;
        struct berval ndn;
        int renamed;    /* Was an existing entry renamed? */
-       int delOldRDN;  /* Was old RDN deleted? */
        Modifications **modlist;        /* the modlist we received */
        Modifications *mods;    /* the modlist we compared */
 } dninfo;
 
+/* return 1 if inserted, 0 otherwise */
+static int
+avl_presentlist_insert(
+       syncinfo_t* si,
+       struct berval *syncUUID )
+{
+       struct berval *syncuuid_bv = ch_malloc( sizeof( struct berval ) + syncUUID->bv_len + 1 );
+
+       syncuuid_bv->bv_len = syncUUID->bv_len;
+       syncuuid_bv->bv_val = (char *)&syncuuid_bv[1];
+       AC_MEMCPY( syncuuid_bv->bv_val, syncUUID->bv_val, syncUUID->bv_len );
+       syncuuid_bv->bv_val[ syncuuid_bv->bv_len ] = '\0';
+
+       if ( avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
+               syncuuid_cmp, avl_dup_error ) )
+       {
+               ch_free( syncuuid_bv );
+               return 0;
+       }
+
+       return 1;
+}
+
 static int
 syncrepl_entry(
        syncinfo_t* si,
@@ -1795,66 +1966,34 @@ syncrepl_entry(
        Entry* entry,
        Modifications** modlist,
        int syncstate,
-       struct berval* syncUUID )
+       struct berval* syncUUID,
+       struct berval* syncCSN )
 {
        Backend *be = op->o_bd;
        slap_callback   cb = { NULL, NULL, NULL, NULL };
-       struct berval   *syncuuid_bv = NULL;
+       int syncuuid_inserted = 0;
        struct berval   syncUUID_strrep = BER_BVNULL;
-       struct berval   uuid_bv = BER_BVNULL;
 
        SlapReply       rs_search = {REP_RESULT};
        SlapReply       rs_delete = {REP_RESULT};
        SlapReply       rs_add = {REP_RESULT};
        SlapReply       rs_modify = {REP_RESULT};
        Filter f = {0};
-#ifdef LDAP_COMP_MATCH
-       AttributeAssertion ava = { NULL, BER_BVNULL, NULL };
-#else
-       AttributeAssertion ava = { NULL, BER_BVNULL };
-#endif
+       AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
        int rc = LDAP_SUCCESS;
 
        struct berval pdn = BER_BVNULL;
        dninfo dni = {0};
        int     retry = 1;
+       int     freecsn = 1;
 
-       switch( syncstate ) {
-       case LDAP_SYNC_PRESENT:
-               Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
-                                       si->si_ridtxt,
-                                       "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_PRESENT)", 0 );
-               break;
-       case LDAP_SYNC_ADD:
-               Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
-                                       si->si_ridtxt,
-                                       "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)", 0 );
-               break;
-       case LDAP_SYNC_DELETE:
-               Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
-                                       si->si_ridtxt,
-                                       "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_DELETE)", 0 );
-               break;
-       case LDAP_SYNC_MODIFY:
-               Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
-                                       si->si_ridtxt,
-                                       "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_MODIFY)", 0 );
-               break;
-       default:
-               Debug( LDAP_DEBUG_ANY, "syncrepl_entry: %s %s\n",
-                                       si->si_ridtxt,
-                                       "LDAP_RES_SEARCH_ENTRY(UNKNOWN syncstate)", 0 );
-       }
+       Debug( LDAP_DEBUG_SYNC,
+               "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s)\n",
+               si->si_ridtxt, syncrepl_state2str( syncstate ), 0 );
 
        if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
-               if ( !si->si_refreshPresent ) {
-                       syncuuid_bv = ber_dupbv( NULL, syncUUID );
-                       if ( avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
-                               syncuuid_cmp, avl_dup_error ) )
-                       {
-                               ber_bvfree( syncuuid_bv );
-                               syncuuid_bv = NULL;
-                       }
+               if ( !si->si_refreshPresent && !si->si_refreshDone ) {
+                       syncuuid_inserted = avl_presentlist_insert( si, syncUUID );
                }
        }
 
@@ -1891,7 +2030,7 @@ syncrepl_entry(
        ava.aa_desc = slap_schema.si_ad_entryUUID;
        ava.aa_value = *syncUUID;
 
-       if ( syncuuid_bv ) {
+       if ( syncuuid_inserted ) {
                Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
                        si->si_ridtxt, syncUUID_strrep.bv_val, 0 );
        }
@@ -1952,11 +2091,18 @@ syncrepl_entry(
                                si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0 );
        }
 
+       assert( BER_BVISNULL( &op->o_csn ) );
+       if ( syncCSN ) {
+               slap_queue_csn( op, syncCSN );
+       }
+
        slap_op_time( &op->o_time, &op->o_tincr );
        switch ( syncstate ) {
        case LDAP_SYNC_ADD:
        case LDAP_SYNC_MODIFY:
+               if ( BER_BVISNULL( &op->o_csn ))
                {
+
                        Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN );
                        if ( a ) {
                                /* FIXME: op->o_csn is assumed to be
@@ -1966,6 +2112,7 @@ syncrepl_entry(
                                 */
                                assert( BER_BVISNULL( &op->o_csn ) );
                                op->o_csn = a->a_vals[0];
+                               freecsn = 0;
                        }
                }
 retry_add:;
@@ -2069,7 +2216,8 @@ retry_add:;
                                op->orr_newSup = NULL;
                                op->orr_nnewSup = NULL;
                        }
-                       op->orr_deleteoldrdn = dni.delOldRDN;
+                       /* Let the modify handler take care of deleting old RDNs */
+                       op->orr_deleteoldrdn = 0;
                        op->orr_modlist = NULL;
                        if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
                                goto done;
@@ -2081,39 +2229,9 @@ retry_add:;
                        noldp = op->orr_nnewrdn;
                        ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
 
-                       /* Setup opattrs too */
-                       {
-                               static AttributeDescription *nullattr = NULL;
-                               static AttributeDescription **const opattrs[] = {
-                                       &slap_schema.si_ad_entryCSN,
-                                       &slap_schema.si_ad_modifiersName,
-                                       &slap_schema.si_ad_modifyTimestamp,
-                                       &nullattr
-                               };
-                               AttributeDescription *opattr;
-                               Modifications *mod, **modtail, **ml;
-                               int i;
-
-                               for ( mod = op->orr_modlist;
-                                       mod->sml_next;
-                                       mod = mod->sml_next )
-                                       ;
-                               modtail = &mod->sml_next;
-
-                               /* pull mod off incoming modlist, append to orr_modlist */
-                               for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
-                                       for ( ml = modlist; *ml; ml = &(*ml)->sml_next )
-                                       {
-                                               if ( (*ml)->sml_desc == opattr ) {
-                                                       mod = *ml;
-                                                       *ml = mod->sml_next;
-                                                       mod->sml_next = NULL;
-                                                       *modtail = mod;
-                                                       modtail = &mod->sml_next;
-                                                       break;
-                                               }
-                                       }
-                               }
+                       /* Remove the CSN for now, only propagate the Modify */
+                       if ( syncCSN ) {
+                               slap_graduate_commit_csn( op );
                        }
                        op->o_bd = si->si_wbe;
                        rc = op->o_bd->be_modrdn( op, &rs_modify );
@@ -2125,7 +2243,12 @@ retry_add:;
                                        "syncrepl_entry: %s be_modrdn (%d)\n", 
                                        si->si_ridtxt, rc, 0 );
                        op->o_bd = be;
-                       goto done;
+                       /* Renamed entries still have other mods so just fallthru */
+                       op->o_req_dn = entry->e_name;
+                       op->o_req_ndn = entry->e_nname;
+                       if ( syncCSN ) {
+                               slap_queue_csn( op, syncCSN );
+                       }
                }
                if ( dni.mods ) {
                        op->o_tag = LDAP_REQ_MODIFY;
@@ -2198,8 +2321,15 @@ done:
        if ( !BER_BVISNULL( &dni.dn ) ) {
                op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
        }
-       if ( entry )
+       if ( entry ) {
                entry_free( entry );
+       }
+       if ( syncCSN ) {
+               slap_graduate_commit_csn( op );
+       }
+       if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) {
+               op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
+       }
        BER_BVZERO( &op->o_csn );
        return rc;
 }
@@ -2217,7 +2347,8 @@ syncrepl_del_nonpresent(
        Operation *op,
        syncinfo_t *si,
        BerVarray uuids,
-       struct berval *cookiecsn )
+       struct sync_cookie *sc,
+       int m )
 {
        Backend* be = op->o_bd;
        slap_callback   cb = { NULL };
@@ -2247,11 +2378,7 @@ syncrepl_del_nonpresent(
 
        if ( uuids ) {
                Filter uf;
-#ifdef LDAP_COMP_MATCH
-               AttributeAssertion eq = { NULL, BER_BVNULL, NULL };
-#else
-               AttributeAssertion eq = { NULL, BER_BVNULL };
-#endif
+               AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
                int i;
 
                op->ors_attrsonly = 1;
@@ -2267,16 +2394,15 @@ syncrepl_del_nonpresent(
 
                for (i=0; uuids[i].bv_val; i++) {
                        op->ors_slimit = 1;
-                       slap_uuidstr_from_normalized( &uf.f_av_value, &uuids[i],
-                               op->o_tmpmemctx );
-                       filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
-                       op->o_tmpfree( uf.f_av_value.bv_val, op->o_tmpmemctx );
                        uf.f_av_value = uuids[i];
+                       filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
                        rc = be->be_search( op, &rs_search );
                        op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
                }
                si->si_refreshDelete ^= NP_DELETE_ONE;
        } else {
+               Filter *cf, *of;
+
                memset( &an[0], 0, 2 * sizeof( AttributeName ) );
                an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
                an[0].an_desc = slap_schema.si_ad_entryUUID;
@@ -2284,21 +2410,56 @@ syncrepl_del_nonpresent(
                op->ors_slimit = SLAP_NO_LIMIT;
                op->ors_attrsonly = 0;
                op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
-               op->ors_filterstr = si->si_filterstr;
+               /* In multimaster, updates can continue to arrive while
+                * we're searching. Limit the search result to entries
+                * older than all of our cookie CSNs.
+                */
+               if ( SLAP_MULTIMASTER( op->o_bd )) {
+                       Filter *f;
+                       int i;
+                       cf = op->o_tmpalloc( (sc->numcsns+1) * sizeof(Filter) +
+                               sc->numcsns * sizeof(AttributeAssertion), op->o_tmpmemctx );
+                       f = cf;
+                       f->f_choice = LDAP_FILTER_AND;
+                       f->f_next = NULL;
+                       f->f_and = f+1;
+                       of = f->f_and;
+                       for ( i=0; i<sc->numcsns; i++ ) {
+                               f = of;
+                               f->f_choice = LDAP_FILTER_LE;
+                               f->f_ava = (AttributeAssertion *)(f+1);
+                               f->f_av_desc = slap_schema.si_ad_entryCSN;
+                               f->f_av_value = sc->ctxcsn[i];
+                               f->f_next = (Filter *)(f->f_ava+1);
+                               of = f->f_next;
+                       }
+                       f->f_next = op->ors_filter;
+                       of = op->ors_filter;
+                       op->ors_filter = cf;
+                       filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
+               } else {
+                       cf = NULL;
+                       op->ors_filterstr = si->si_filterstr;
+               }
                op->o_nocaching = 1;
 
                if ( limits_check( op, &rs_search ) == 0 ) {
                        rc = be->be_search( op, &rs_search );
                }
-               if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
+               if ( SLAP_MULTIMASTER( op->o_bd )) {
+                       op->o_tmpfree( cf, op->o_tmpmemctx );
+                       op->ors_filter = of;
+               }
+               if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
+
        }
 
        op->o_nocaching = 0;
 
        if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
 
-               if ( cookiecsn && !BER_BVISNULL( cookiecsn ) ) {
-                       csn = *cookiecsn;
+               if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
+                       csn = sc->ctxcsn[m];
                } else {
                        csn = si->si_syncCookie.ctxcsn[0];
                }
@@ -2328,6 +2489,7 @@ syncrepl_del_nonpresent(
                                mod1.sml_flags = 0;
                                mod1.sml_desc = slap_schema.si_ad_objectClass;
                                mod1.sml_type = mod1.sml_desc->ad_cname;
+                               mod1.sml_numvals = 2;
                                mod1.sml_values = &gcbva[0];
                                mod1.sml_nvalues = NULL;
                                mod1.sml_next = &mod2;
@@ -2336,6 +2498,7 @@ syncrepl_del_nonpresent(
                                mod2.sml_flags = 0;
                                mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
                                mod2.sml_type = mod2.sml_desc->ad_cname;
+                               mod2.sml_numvals = 1;
                                mod2.sml_values = &gcbva[1];
                                mod2.sml_nvalues = NULL;
                                mod2.sml_next = NULL;
@@ -2369,6 +2532,10 @@ syncrepl_del_nonpresent(
                        ber_bvfree( np_prev->npe_name );
                        ber_bvfree( np_prev->npe_nname );
                        ch_free( np_prev );
+
+                       if ( slapd_shutdown ) {
+                               break;
+                       }
                }
 
                slap_graduate_commit_csn( op );
@@ -2459,6 +2626,7 @@ syncrepl_add_glue(
 
                a = attr_alloc( slap_schema.si_ad_objectClass );
 
+               a->a_numvals = 2;
                a->a_vals = ch_calloc( 3, sizeof( struct berval ) );
                ber_dupbv( &a->a_vals[0], &gcbva[0] );
                ber_dupbv( &a->a_vals[1], &gcbva[1] );
@@ -2471,6 +2639,7 @@ syncrepl_add_glue(
 
                a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
 
+               a->a_numvals = 1;
                a->a_vals = ch_calloc( 2, sizeof( struct berval ) );
                ber_dupbv( &a->a_vals[0], &gcbva[1] );
                ber_dupbv( &a->a_vals[1], &gcbva[2] );
@@ -2536,30 +2705,32 @@ syncrepl_updateCookie(
        struct sync_cookie *syncCookie )
 {
        Backend *be = op->o_bd;
-       Modifications mod[2];
+       Modifications mod;
        struct berval first = BER_BVNULL;
 
-       int rc, i, j, len;
+       int rc, i, j;
+       ber_len_t len;
 
        slap_callback cb = { NULL };
        SlapReply       rs_modify = {REP_RESULT};
 
-       mod[0].sml_op = LDAP_MOD_DELETE;
-       mod[0].sml_desc = slap_schema.si_ad_contextCSN;
-       mod[0].sml_type = mod[0].sml_desc->ad_cname;
-       mod[0].sml_values = NULL;
-       mod[0].sml_nvalues = NULL;
-       mod[0].sml_next = &mod[1];
-
-       mod[1].sml_op = LDAP_MOD_ADD;
-       mod[1].sml_desc = slap_schema.si_ad_contextCSN;
-       mod[1].sml_type = mod[0].sml_desc->ad_cname;
-       mod[1].sml_values = NULL;
-       mod[1].sml_nvalues = NULL;
-       mod[1].sml_next = NULL;
+       mod.sml_op = LDAP_MOD_REPLACE;
+       mod.sml_desc = slap_schema.si_ad_contextCSN;
+       mod.sml_type = mod.sml_desc->ad_cname;
+       mod.sml_flags = SLAP_MOD_INTERNAL;
+       mod.sml_nvalues = NULL;
+       mod.sml_next = NULL;
 
        ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
 
+       /* clone the cookieState CSNs so we can Replace the whole thing */
+       mod.sml_numvals = si->si_cookieState->cs_num;
+       mod.sml_values = op->o_tmpalloc(( mod.sml_numvals+1 )*sizeof(struct berval), op->o_tmpmemctx );
+       for ( i=0; i<mod.sml_numvals; i++ )
+               mod.sml_values[i] = si->si_cookieState->cs_vals[i];
+       BER_BVZERO( &mod.sml_values[i] );
+
+       /* find any CSNs in the syncCookie that are newer than the cookieState */
        for ( i=0; i<syncCookie->numcsns; i++ ) {
                for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
                        if ( syncCookie->sids[i] != si->si_cookieState->cs_sids[j] )
@@ -2569,26 +2740,35 @@ syncrepl_updateCookie(
                                len = si->si_cookieState->cs_vals[j].bv_len;
                        if ( memcmp( syncCookie->ctxcsn[i].bv_val,
                                si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
-                               ber_bvarray_add_x( &mod[0].sml_values,
-                                       &si->si_cookieState->cs_vals[j], op->o_tmpmemctx );
-                               ber_bvarray_add_x( &mod[1].sml_values,
-                                       &syncCookie->ctxcsn[i], op->o_tmpmemctx );
-                               if ( BER_BVISNULL( &first ))
+                               mod.sml_values[j] = syncCookie->ctxcsn[i];
+                               if ( BER_BVISNULL( &first ) ) {
+                                       first = syncCookie->ctxcsn[i];
+
+                               } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+                               {
                                        first = syncCookie->ctxcsn[i];
+                               }
                        }
                        break;
                }
                /* there was no match for this SID, it's a new CSN */
                if ( j == si->si_cookieState->cs_num ) {
-                       ber_bvarray_add_x( &mod[1].sml_values,
-                               &syncCookie->ctxcsn[i], op->o_tmpmemctx );
-                       if ( BER_BVISNULL( &first ))
+                       mod.sml_values = op->o_tmprealloc( mod.sml_values,
+                               ( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
+                       mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
+                       BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
+                       if ( BER_BVISNULL( &first ) ) {
+                               first = syncCookie->ctxcsn[i];
+                       } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+                       {
                                first = syncCookie->ctxcsn[i];
+                       }
                }
        }
        /* Should never happen, ITS#5065 */
        if ( BER_BVISNULL( &first )) {
                ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+               op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
                return 0;
        }
        op->o_bd = si->si_wbe;
@@ -2604,37 +2784,27 @@ syncrepl_updateCookie(
        op->o_req_ndn = op->o_bd->be_nsuffix[0];
 
        /* update contextCSN */
-       op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
-
-       if ( mod[0].sml_values )
-               op->orm_modlist = mod;
-       else
-               op->orm_modlist = &mod[1];
+       op->o_dont_replicate = 1;
 
+       op->orm_modlist = &mod;
        op->orm_no_opattrs = 1;
        rc = op->o_bd->be_modify( op, &rs_modify );
        op->orm_no_opattrs = 0;
-       op->o_msgid = 0;
+       op->o_dont_replicate = 0;
 
        if ( rs_modify.sr_err == LDAP_SUCCESS ) {
                slap_sync_cookie_free( &si->si_syncCookie, 0 );
                slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
                /* If we replaced any old values */
-               if ( mod[0].sml_values ) {
-                       for ( i=0; !BER_BVISNULL( &mod[0].sml_values[i] ); i++ ) {
-                               for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
-                                       if ( mod[0].sml_values[i].bv_val !=
-                                               si->si_cookieState->cs_vals[j].bv_val )
-                                               continue;
-                                       ber_bvreplace( &si->si_cookieState->cs_vals[j],
-                                               &mod[1].sml_values[i] );
-                                       break;
-                               }
-                       }
-               } else {
-                       /* Else we just added */
-                       si->si_cookieState->cs_num += syncCookie->numcsns;
-                       value_add( &si->si_cookieState->cs_vals, syncCookie->ctxcsn );
+               for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
+                       if ( mod.sml_values[i].bv_val != si->si_cookieState->cs_vals[i].bv_val )
+                                       ber_bvreplace( &si->si_cookieState->cs_vals[i],
+                                               &mod.sml_values[i] );
+               }
+               /* Handle any added values */
+               if ( i < mod.sml_numvals ) {
+                       si->si_cookieState->cs_num = mod.sml_numvals;
+                       value_add( &si->si_cookieState->cs_vals, &mod.sml_values[i] );
                        free( si->si_cookieState->cs_sids );
                        si->si_cookieState->cs_sids = slap_parse_csn_sids(
                                si->si_cookieState->cs_vals, si->si_cookieState->cs_num, NULL );
@@ -2649,13 +2819,11 @@ syncrepl_updateCookie(
        }
        ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
 
-       slap_graduate_commit_csn( op );
        op->o_bd = be;
        op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
        BER_BVZERO( &op->o_csn );
-       if ( mod[1].sml_next ) slap_mods_free( mod[1].sml_next, 1 );
-       op->o_tmpfree( mod[1].sml_values, op->o_tmpmemctx );
-       op->o_tmpfree( mod[0].sml_values, op->o_tmpmemctx );
+       if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
+       op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
 
        return rc;
 }
@@ -2670,76 +2838,82 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
        modtail = *mret;
 
        if ( old ) {
-               int n, o, d, a, *adds, *dels;
+               int n, o, nn, no;
+               struct berval **adds, **dels;
                /* count old and new */
                for ( o=0; old->a_vals[o].bv_val; o++ ) ;
                for ( n=0; new->a_vals[n].bv_val; n++ ) ;
 
-               adds = op->o_tmpalloc( sizeof(int) * n, op->o_tmpmemctx );
-               dels = op->o_tmpalloc( sizeof(int) * o, op->o_tmpmemctx );
-               d = 0;
-               a = 0;
-               i = 0;
+               /* there MUST be both old and new values */
+               assert( o != 0 );
+               assert( n != 0 );
                j = 0;
 
-               while ( i < o && j < n ) {
-                       int k;
-                       if ( bvmatch( &old->a_vals[i], &new->a_vals[j] ) ) {
-                               i++;
-                               j++;
-                               continue;
-                       }
-                       for ( k = j + 1; k<n; k++ ) {
-                               if ( bvmatch( &old->a_vals[i], &new->a_vals[k] ) ) {
-                                       break;
-                               }
-                       }
-                       /* an old value was deleted */
-                       if ( k == n ) {
-                               dels[d++] = i++;
-                               continue;
-                       }
-                       /* old value still exists, move to next */
-                       i++;
-                       for ( k = i; k < o; k++ ) {
-                               if ( bvmatch( &old->a_vals[k], &new->a_vals[j] ) ) {
+               adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx );
+               dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx );
+
+               for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i];
+               for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i];
+
+               nn = n; no = o;
+
+               for ( i=0; i<o; i++ ) {
+                       for ( j=0; j<n; j++ ) {
+                               if ( !adds[j] )
+                                       continue;
+                               if ( bvmatch( dels[i], adds[j] ) ) {
+                                       no--;
+                                       nn--;
+                                       adds[j] = NULL;
+                                       dels[i] = NULL;
                                        break;
                                }
                        }
-                       if ( k == o ) {
-                               adds[a++] = j++;
-                       }
                }
-               while ( i < o )
-                       dels[d++] = i++;
-               while ( j < n )
-                       adds[a++] = j++;
 
+               /* Don't delete/add an objectClass, always use the replace op.
+                * Modify would fail if provider has replaced entry with a new,
+                * and the new explicitly includes a superior of a class that was
+                * only included implicitly in the old entry.  Ref ITS#5517.
+                *
+                * Also use replace op if attr has no equality matching rule.
+                * (ITS#5781)
+                */
+               if ( nn && no < o &&
+                       ( old->a_desc == slap_schema.si_ad_objectClass ||
+                        !old->a_desc->ad_type->sat_equality ))
+                       no = o;
+
+               i = j;
                /* all old values were deleted, just use the replace op */
-               if ( d == o ) {
+               if ( no == o ) {
                        i = j-1;
-               } else if ( d ) {
+               } else if ( no ) {
                /* delete some values */
                        mod = ch_malloc( sizeof( Modifications ) );
                        mod->sml_op = LDAP_MOD_DELETE;
                        mod->sml_flags = 0;
                        mod->sml_desc = old->a_desc;
                        mod->sml_type = mod->sml_desc->ad_cname;
-                       mod->sml_values = ch_malloc( ( d + 1 ) * sizeof(struct berval) );
+                       mod->sml_numvals = no;
+                       mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
                        if ( old->a_vals != old->a_nvals ) {
-                               mod->sml_nvalues = ch_malloc( ( d + 1 ) * sizeof(struct berval) );
+                               mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
                        } else {
                                mod->sml_nvalues = NULL;
                        }
-                       for ( i = 0; i < d; i++ ) {
-                               ber_dupbv( &mod->sml_values[i], &old->a_vals[dels[i]] );
+                       j = 0;
+                       for ( i = 0; i < o; i++ ) {
+                               if ( !dels[i] ) continue;
+                               ber_dupbv( &mod->sml_values[j], &old->a_vals[i] );
                                if ( mod->sml_nvalues ) {
-                                       ber_dupbv( &mod->sml_nvalues[i], &old->a_nvals[dels[i]] );
+                                       ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] );
                                }
+                               j++;
                        }
-                       BER_BVZERO( &mod->sml_values[i] );
+                       BER_BVZERO( &mod->sml_values[j] );
                        if ( mod->sml_nvalues ) {
-                               BER_BVZERO( &mod->sml_nvalues[i] );
+                               BER_BVZERO( &mod->sml_nvalues[j] );
                        }
                        *modtail = mod;
                        modtail = &mod->sml_next;
@@ -2747,27 +2921,31 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
                }
                op->o_tmpfree( dels, op->o_tmpmemctx );
                /* some values were added */
-               if ( a && d < o ) {
+               if ( nn && no < o ) {
                        mod = ch_malloc( sizeof( Modifications ) );
                        mod->sml_op = LDAP_MOD_ADD;
                        mod->sml_flags = 0;
                        mod->sml_desc = old->a_desc;
                        mod->sml_type = mod->sml_desc->ad_cname;
-                       mod->sml_values = ch_malloc( ( a + 1 ) * sizeof(struct berval) );
+                       mod->sml_numvals = nn;
+                       mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
                        if ( old->a_vals != old->a_nvals ) {
-                               mod->sml_nvalues = ch_malloc( ( a + 1 ) * sizeof(struct berval) );
+                               mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
                        } else {
                                mod->sml_nvalues = NULL;
                        }
-                       for ( i = 0; i < a; i++ ) {
-                               ber_dupbv( &mod->sml_values[i], &new->a_vals[adds[i]] );
+                       j = 0;
+                       for ( i = 0; i < n; i++ ) {
+                               if ( !adds[i] ) continue;
+                               ber_dupbv( &mod->sml_values[j], &new->a_vals[i] );
                                if ( mod->sml_nvalues ) {
-                                       ber_dupbv( &mod->sml_nvalues[i], &new->a_nvals[adds[i]] );
+                                       ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] );
                                }
+                               j++;
                        }
-                       BER_BVZERO( &mod->sml_values[i] );
+                       BER_BVZERO( &mod->sml_values[j] );
                        if ( mod->sml_nvalues ) {
-                               BER_BVZERO( &mod->sml_nvalues[i] );
+                               BER_BVZERO( &mod->sml_nvalues[j] );
                        }
                        *modtail = mod;
                        modtail = &mod->sml_next;
@@ -2815,39 +2993,32 @@ dn_callback(
                        if ( dni->new_entry ) {
                                Modifications **modtail, **ml;
                                Attribute *old, *new;
-                               int i, is_ctx;
+                               struct berval old_rdn, new_rdn;
+                               struct berval old_p, new_p;
+                               int is_ctx;
 
                                is_ctx = dn_match( &rs->sr_entry->e_nname,
                                        &op->o_bd->be_nsuffix[0] );
 
                                /* Did the DN change?
+                                * case changes in the parent are ignored,
+                                * we only want to know if the RDN was
+                                * actually changed.
                                 */
-                               if ( !dn_match( &rs->sr_entry->e_name,
-                                               &dni->new_entry->e_name ) )
-                               {
-                                       struct berval oldRDN, oldVal;
-                                       AttributeDescription *ad = NULL;
-                                       Attribute *a;
+                               dnRdn( &rs->sr_entry->e_name, &old_rdn );
+                               dnRdn( &dni->new_entry->e_name, &new_rdn );
+                               dnParent( &rs->sr_entry->e_nname, &old_p );
+                               dnParent( &dni->new_entry->e_nname, &new_p );
 
+                               if ( !dn_match( &old_rdn, &new_rdn ) ||
+                                       ber_bvstrcasecmp( &old_p, &new_p ))
+                               {
                                        dni->renamed = 1;
-                                       /* See if the oldRDN was deleted */
-                                       dnRdn( &rs->sr_entry->e_nname, &oldRDN );
-                                       oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
-                                       oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
-                                               oldRDN.bv_val );
-                                       oldRDN.bv_len -= oldVal.bv_len + 2;
-                                       slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
-                                       a = attr_find( dni->new_entry->e_attrs, ad );
-                                       if ( !a || value_find_ex( ad,
-                                               SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
-                                               SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
-                                               SLAP_MR_VALUE_OF_SYNTAX, a->a_nvals,
-                                               &oldVal, op->o_tmpmemctx ) != LDAP_SUCCESS )
-                                       {
-                                               dni->delOldRDN = 1;
-                                       }
-                                       /* OK, this was just a modDN, we're done */
-                                       return LDAP_SUCCESS;
+
+                                       /* A ModDN has happened, but other changes may have
+                                        * occurred before we picked it up. So fallthru to
+                                        * regular Modify processing.
+                                        */
                                }
 
                                modtail = &dni->mods;
@@ -2859,11 +3030,13 @@ dn_callback(
                                new = attr_find( dni->new_entry->e_attrs,
                                        slap_schema.si_ad_entryCSN );
                                if ( new && old ) {
-                                       int len = old->a_vals[0].bv_len;
+                                       int rc;
+                                       ber_len_t len = old->a_vals[0].bv_len;
                                        if ( len > new->a_vals[0].bv_len )
                                                len = new->a_vals[0].bv_len;
-                                       if ( memcmp( old->a_vals[0].bv_val,
-                                               new->a_vals[0].bv_val, len ) >= 0 ) {
+                                       rc = memcmp( old->a_vals[0].bv_val,
+                                               new->a_vals[0].bv_val, len );
+                                       if ( rc > 0 ) {
                                                Debug( LDAP_DEBUG_SYNC,
                                                        "dn_callback : new entry is older than ours "
                                                        "%s ours %s, new %s\n",
@@ -2871,6 +3044,13 @@ dn_callback(
                                                        old->a_vals[0].bv_val,
                                                        new->a_vals[0].bv_val );
                                                return LDAP_SUCCESS;
+                                       } else if ( rc == 0 ) {
+                                               Debug( LDAP_DEBUG_SYNC,
+                                                       "dn_callback : entries have identical CSN "
+                                                       "%s %s\n",
+                                                       rs->sr_entry->e_name.bv_val,
+                                                       old->a_vals[0].bv_val, 0 );
+                                               return LDAP_SUCCESS;
                                        }
                                }
 
@@ -2920,6 +3100,7 @@ dn_callback(
                                                        mod->sml_flags = 0;
                                                        mod->sml_desc = old->a_desc;
                                                        mod->sml_type = mod->sml_desc->ad_cname;
+                                                       mod->sml_numvals = 0;
                                                        mod->sml_values = NULL;
                                                        mod->sml_nvalues = NULL;
                                                        *modtail = mod;
@@ -2967,13 +3148,11 @@ nonpresent_callback(
        struct nonpresent_entry *np_entry;
 
        if ( rs->sr_type == REP_RESULT ) {
-               count = avl_free( si->si_presentlist, avl_ber_bvfree );
+               count = avl_free( si->si_presentlist, ch_free );
                si->si_presentlist = NULL;
 
        } else if ( rs->sr_type == REP_SEARCH ) {
                if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
-                       char buf[sizeof("rid=000 not")];
-
                        a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
 
                        if ( a ) {
@@ -2981,13 +3160,15 @@ nonpresent_callback(
                                        syncuuid_cmp );
                        }
 
-                       if ( slap_debug & LDAP_DEBUG_SYNC ) {
-                               sprintf( buf, "%s %s", si->si_ridtxt,
-                                       present_uuid ? "got" : "not" );
-                       }
+                       if ( LogTest( LDAP_DEBUG_SYNC ) ) {
+                               char buf[sizeof("rid=999 non")];
 
-                       Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s UUID %s, dn %s\n",
-                               buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
+                               snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
+                                       present_uuid ? "" : "non" );
+
+                               Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %spresent UUID %s, dn %s\n",
+                                       buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
+                       }
 
                        if ( a == NULL ) return 0;
                }
@@ -3001,8 +3182,7 @@ nonpresent_callback(
 
                } else {
                        avl_delete( &si->si_presentlist,
-                                       &a->a_nvals[0], syncuuid_cmp );
-                       ch_free( present_uuid->bv_val );
+                               &a->a_nvals[0], syncuuid_cmp );
                        ch_free( present_uuid );
                }
        }
@@ -3033,6 +3213,7 @@ slap_uuidstr_from_normalized(
        struct berval* normalized,
        void *ctx )
 {
+#if 0
        struct berval *new;
        unsigned char nibble;
        int i, d = 0;
@@ -3080,6 +3261,52 @@ slap_uuidstr_from_normalized(
        }
 
        new->bv_val[new->bv_len] = '\0';
+       return new;
+#endif
+
+       struct berval   *new;
+       int             rc = 0;
+
+       if ( normalized == NULL ) return NULL;
+       if ( normalized->bv_len != 16 ) return NULL;
+
+       if ( uuidstr ) {
+               new = uuidstr;
+
+       } else {
+               new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
+               if ( new == NULL ) {
+                       return NULL;
+               }
+       }
+
+       new->bv_len = 36;
+
+       if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
+               rc = 1;
+               goto done;
+       }
+
+       rc = lutil_uuidstr_from_normalized( normalized->bv_val,
+               normalized->bv_len, new->bv_val, new->bv_len + 1 );
+
+done:;
+       if ( rc == -1 ) {
+               if ( new != NULL ) {
+                       if ( new->bv_val != NULL ) {
+                               slap_sl_free( new->bv_val, ctx );
+                       }
+
+                       if ( new != uuidstr ) {
+                               slap_sl_free( new, ctx );
+                       }
+               }
+               new = NULL;
+
+       } else {
+               new->bv_len = rc;
+       }
+
        return new;
 }
 
@@ -3093,18 +3320,6 @@ syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
        return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
 }
 
-static void
-avl_ber_bvfree( void *v_bv )
-{
-       struct berval   *bv = (struct berval *)v_bv;
-       
-       if( v_bv == NULL ) return;
-       if ( !BER_BVISNULL( bv ) ) {
-               ch_free( bv->bv_val );
-       }
-       ch_free( (char *) bv );
-}
-
 void
 syncinfo_free( syncinfo_t *sie, int free_all )
 {
@@ -3120,16 +3335,15 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                si_next = sie->si_next;
 
                if ( sie->si_ld ) {
-                       if ( sie->si_conn_setup ) {
-                               ber_socket_t s;
-                               ldap_get_option( sie->si_ld, LDAP_OPT_DESC, &s );
-                               connection_client_stop( s );
-                               sie->si_conn_setup = 0;
+                       if ( sie->si_conn ) {
+                               connection_client_stop( sie->si_conn );
+                               sie->si_conn = NULL;
                        }
                        ldap_unbind_ext( sie->si_ld, NULL, NULL );
                }
        
                /* re-fetch it, in case it was already removed */
+               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
                sie->si_re = ldap_pvt_runqueue_find( &slapd_rq, do_syncrepl, sie );
                if ( sie->si_re ) {
                        if ( ldap_pvt_runqueue_isrunning( &slapd_rq, sie->si_re ) )
@@ -3137,6 +3351,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                        ldap_pvt_runqueue_remove( &slapd_rq, sie->si_re );
                }
        
+               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
                ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
        
                bindconf_free( &sie->si_bindconf );
@@ -3196,7 +3411,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                }
                slap_sync_cookie_free( &sie->si_syncCookie, 0 );
                if ( sie->si_presentlist ) {
-                   avl_free( sie->si_presentlist, avl_ber_bvfree );
+                   avl_free( sie->si_presentlist, ch_free );
                }
                while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
                        struct nonpresent_entry* npe;
@@ -3298,10 +3513,10 @@ parse_syncrepl_line(
                                Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
                                return -1;
                        }
-                       if ( tmp >= 1000 || tmp < 0 ) {
+                       if ( tmp > SLAP_SYNC_SID_MAX || tmp < 0 ) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                        "Error: parse_syncrepl_line: "
-                                       "syncrepl id %d is out of range [0..999]", tmp );
+                                       "syncrepl id %d is out of range [0..4095]", tmp );
                                Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
                                return -1;
                        }
@@ -3358,8 +3573,9 @@ parse_syncrepl_line(
                                Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
                                return -1;
                        }
-                       if ( select_backend( &si->si_base, 0 ) != c->be ) {
-                               ber_memfree( si->si_base.bv_val );
+                       if ( !be_issubordinate( c->be, &si->si_base ) ) {
+                               ch_free( si->si_base.bv_val );
+                               BER_BVZERO( &si->si_base );
                                snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                        "Base DN \"%s\" is not within the database naming context",
                                        val );
@@ -3423,7 +3639,7 @@ parse_syncrepl_line(
                                si->si_anfile = attr_fname;
                        } else {
                                char *str, *s, *next;
-                               char delimstr[] = " ,\t";
+                               const char *delimstr = " ,\t";
                                str = ch_strdup( val );
                                for ( s = ldap_pvt_strtok( str, delimstr, &next );
                                                s != NULL;
@@ -3492,12 +3708,10 @@ parse_syncrepl_line(
                                si->si_interval = 0;
                        } else if ( strchr( val, ':' ) != NULL ) {
                                char *next, *ptr = val;
-                               unsigned dd, hh, mm, ss;
+                               int dd, hh, mm, ss;
 
-                               /* NOTE: the test for ptr[ 0 ] == '-'
-                                * should go before the call to strtoul() */
-                               dd = strtoul( ptr, &next, 10 );
-                               if ( ptr[ 0 ] == '-' || next == ptr || next[0] != ':' ) {
+                               dd = strtol( ptr, &next, 10 );
+                               if ( next == ptr || next[0] != ':' || dd < 0 ) {
                                        snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                                "Error: parse_syncrepl_line: "
                                                "invalid interval \"%s\", unable to parse days", val );
@@ -3505,8 +3719,8 @@ parse_syncrepl_line(
                                        return -1;
                                }
                                ptr = next + 1;
-                               hh = strtoul( ptr, &next, 10 );
-                               if ( ptr[ 0 ] == '-' || next == ptr || next[0] != ':' || hh > 24 ) {
+                               hh = strtol( ptr, &next, 10 );
+                               if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) {
                                        snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                                "Error: parse_syncrepl_line: "
                                                "invalid interval \"%s\", unable to parse hours", val );
@@ -3514,8 +3728,8 @@ parse_syncrepl_line(
                                        return -1;
                                }
                                ptr = next + 1;
-                               mm = strtoul( ptr, &next, 10 );
-                               if ( ptr[ 0 ] == '-' || next == ptr || next[0] != ':' || mm > 60 ) {
+                               mm = strtol( ptr, &next, 10 );
+                               if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) {
                                        snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                                "Error: parse_syncrepl_line: "
                                                "invalid interval \"%s\", unable to parse minutes", val );
@@ -3523,8 +3737,8 @@ parse_syncrepl_line(
                                        return -1;
                                }
                                ptr = next + 1;
-                               ss = strtoul( ptr, &next, 10 );
-                               if ( ptr[ 0 ] == '-' || next == ptr || next[0] != '\0' || ss > 60 ) {
+                               ss = strtol( ptr, &next, 10 );
+                               if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) {
                                        snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                                "Error: parse_syncrepl_line: "
                                                "invalid interval \"%s\", unable to parse seconds", val );
@@ -3741,7 +3955,6 @@ add_syncrepl(
        si->si_manageDSAit = 0;
        si->si_tlimit = 0;
        si->si_slimit = 0;
-       si->si_conn_setup = 0;
 
        si->si_presentlist = NULL;
        LDAP_LIST_INIT( &si->si_nonpresentlist );
@@ -3789,9 +4002,11 @@ add_syncrepl(
 
                        if ( !isMe ) {
                                init_syncrepl( si );
+                               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
                                si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
                                        si->si_interval, do_syncrepl, si, "do_syncrepl",
                                        si->si_ridtxt );
+                               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
                                if ( si->si_re )
                                        rc = config_sync_shadow( c ) ? -1 : 0;
                                else
@@ -3816,9 +4031,6 @@ add_syncrepl(
                        "Config: ** successfully added syncrepl \"%s\"\n",
                        BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
                        "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
-               if ( !si->si_schemachecking ) {
-                       SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
-               }
                if ( c->be->be_syncinfo ) {
                        si->si_cookieState = c->be->be_syncinfo->si_cookieState;
                } else {
@@ -3836,9 +4048,9 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 {
        struct berval bc, uri;
        char buf[BUFSIZ*2], *ptr;
+       ber_len_t len;
        int i;
-
-#define WHATSLEFT      ( sizeof( buf ) - ( ptr - buf ) )
+#      define WHATSLEFT        ((ber_len_t) (&buf[sizeof( buf )] - ptr))
 
        BER_BVZERO( bv );
 
@@ -3851,9 +4063,11 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
        si->si_bindconf.sb_version = LDAP_VERSION3;
 
        ptr = buf;
-       ptr += snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
+       assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
+       len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
                si->si_rid, si->si_bindconf.sb_uri.bv_val );
-       if ( ptr - buf >= sizeof( buf ) ) return;
+       if ( len >= sizeof( buf ) ) return;
+       ptr += len;
        if ( !BER_BVISNULL( &bc ) ) {
                if ( WHATSLEFT <= bc.bv_len ) {
                        free( bc.bv_val );
@@ -3911,8 +4125,8 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
                if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
                ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
                old = ptr;
-               /* FIXME: add check for overflow */
                ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
+               if ( ptr == NULL ) return;
                if ( si->si_allattrs ) {
                        if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
                        if ( old != ptr ) *ptr++ = ',';
@@ -3928,8 +4142,8 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
        if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
                if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
                ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
-               /* FIXME: add check for overflow */
                ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
+               if ( ptr == NULL ) return;
        }
        if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
        ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
@@ -3950,36 +4164,42 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
                dd /= 60;
                hh = dd % 24;
                dd /= 24;
-               ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
-               ptr += snprintf( ptr, WHATSLEFT, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
-               if ( ptr - buf >= sizeof( buf ) ) return;
+               len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
+                       INTERVALSTR, dd, hh, mm, ss );
+               if ( len >= WHATSLEFT ) return;
+               ptr += len;
        } else if ( si->si_retryinterval ) {
-               int space=0;
+               const char *space = "";
                if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
                ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
                for (i=0; si->si_retryinterval[i]; i++) {
-                       if ( space ) *ptr++ = ' ';
-                       space = 1;
-                       ptr += snprintf( ptr, WHATSLEFT, "%ld ", (long) si->si_retryinterval[i] );
+                       len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
+                               (long) si->si_retryinterval[i] );
+                       space = " ";
+                       if ( WHATSLEFT - 1 <= len ) return;
+                       ptr += len;
                        if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
                                *ptr++ = '+';
-                       else
-                               ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+                       else {
+                               len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+                               if ( WHATSLEFT <= len ) return;
+                               ptr += len;
+                       }
                }
                if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
                *ptr++ = '"';
        }
 
        if ( si->si_slimit ) {
-               if ( WHATSLEFT <= STRLENOF( " " SLIMITSTR "=" ) ) return;
-               ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
-               ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_slimit );
+               len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
+               if ( WHATSLEFT <= len ) return;
+               ptr += len;
        }
 
        if ( si->si_tlimit ) {
-               if ( WHATSLEFT <= STRLENOF( " " TLIMITSTR "=" ) ) return;
-               ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
-               ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_tlimit );
+               len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
+               if ( WHATSLEFT <= len ) return;
+               ptr += len;
        }
 
        if ( si->si_syncdata ) {
@@ -4019,13 +4239,18 @@ syncrepl_config( ConfigArgs *c )
                        for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
                                si = *sip;
                                if ( c->valx == -1 || i == c->valx ) {
+                                       int isrunning = 0;
                                        *sip = si->si_next;
                                        /* If the task is currently active, we have to leave
                                         * it running. It will exit on its own. This will only
                                         * happen when running on the cn=config DB.
                                         */
-                                       if ( si->si_re &&
-                                               ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re ) ) {
+                                       if ( si->si_re ) {
+                                               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+                                               isrunning = ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re );
+                                               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+                                       }
+                                       if ( si->si_re && isrunning ) {
                                                si->si_ctype = 0;
                                        } else {
                                                syncinfo_free( si, 0 );