]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
fix previous commit (ITS#5819)
[openldap] / servers / slapd / syncrepl.c
index c11b15d6c09f2bfffad4fb46c3ba8422fb666dcf..a9f9cf66cc8ca86ff031b14efca36a15e7e59fd5 100644 (file)
@@ -106,7 +106,7 @@ typedef struct syncinfo_s {
 
 static int syncuuid_cmp( const void *, const void * );
 static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
-static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct berval * );
+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(
@@ -407,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;
        }
@@ -432,6 +432,112 @@ ldap_sync_search(
        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,
@@ -462,15 +568,25 @@ 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;
-       si->si_syncCookie.sid = SLAP_SINGLE_SHADOW( si->si_be ) ? -1 :
-               slap_serverID;
+
+       /* 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.
@@ -538,104 +654,8 @@ 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];
-               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 );
-               rc = backend_operational( op, &rs );
-               if ( rc == 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 );
+               /* Look for contextCSN from syncprov overlay. */
+               check_syncprov( op, si );
        }
 
        si->si_refreshDone = 0;
@@ -672,8 +692,8 @@ 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,
@@ -686,6 +706,11 @@ compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
                        }
                        break;
                }
+               if ( i == sc1->numcsns ) {
+                       /* sc2 has a sid sc1 lacks */
+                       *which = j;
+                       return -1;
+               }
        }
        return match;
 }
@@ -834,10 +859,17 @@ do_syncrep2(
                                        syncCookie.ctxcsn )
                                {
                                        rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                               } else if ( rc == LDAP_NO_SUCH_OBJECT ) {
-                                       rc = LDAP_SYNC_REFRESH_REQUIRED;
-                                       si->si_logstate = SYNCLOG_FALLBACK;
-                                       ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+                               } 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 )
@@ -882,6 +914,11 @@ do_syncrep2(
                                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 );
@@ -908,6 +945,10 @@ do_syncrep2(
                                }
                                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 ) {
@@ -925,10 +966,11 @@ do_syncrep2(
                                 *      2) on err policy : stop service, stop sync, retry
                                 */
                                if ( refreshDeletes == 0 && match < 0 &&
-                                       err == LDAP_SUCCESS )
+                                       err == LDAP_SUCCESS &&
+                                       syncCookie_req.numcsns == syncCookie.numcsns )
                                {
                                        syncrepl_del_nonpresent( op, si, NULL,
-                                               &syncCookie.ctxcsn[m] );
+                                               &syncCookie, m );
                                } else {
                                        avl_free( si->si_presentlist, ch_free );
                                        si->si_presentlist = NULL;
@@ -1039,7 +1081,7 @@ do_syncrep2(
                                        ber_scanf( ber, /*"{"*/ "}" );
                                        if ( refreshDeletes ) {
                                                syncrepl_del_nonpresent( op, si, syncUUIDs,
-                                                       &syncCookie.ctxcsn[m] );
+                                                       &syncCookie, m );
                                                ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
                                        } else {
                                                int i;
@@ -1060,6 +1102,10 @@ do_syncrep2(
                                        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;
                                } else if ( !syncCookie_req.ctxcsn ) {
@@ -1070,9 +1116,10 @@ do_syncrep2(
                                }
 
                                if ( match < 0 ) {
-                                       if ( si->si_refreshPresent == 1 ) {
+                                       if ( si->si_refreshPresent == 1 &&
+                                               syncCookie_req.numcsns == syncCookie.numcsns ) {
                                                syncrepl_del_nonpresent( op, si, NULL,
-                                                       &syncCookie.ctxcsn[m] );
+                                                       &syncCookie, m );
                                        }
 
                                        if ( syncCookie.ctxcsn )
@@ -1167,9 +1214,8 @@ do_syncrepl(
        if ( si == NULL )
                return NULL;
 
-       /* Don't wait around if there's a previous session still running */
-       if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex ))
-               return NULL;
+       /* There will never be more than one instance active */
+       ldap_pvt_thread_mutex_lock( &si->si_mutex );
 
        switch( abs( si->si_type ) ) {
        case LDAP_SYNC_REFRESH_ONLY:
@@ -1201,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 );
        }
 
@@ -1228,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 );
@@ -1282,6 +1352,7 @@ reload:
        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 ) {
@@ -1861,7 +1932,6 @@ 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;
@@ -2146,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;
@@ -2158,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 );
@@ -2202,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;
@@ -2301,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 };
@@ -2354,6 +2401,8 @@ syncrepl_del_nonpresent(
                }
                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;
@@ -2361,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];
                }
@@ -2621,32 +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_numvals = 0;
-       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_numvals = 0;
-       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] )
@@ -2656,29 +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 );
-                               mod[0].sml_numvals++;
-                               ber_bvarray_add_x( &mod[1].sml_values,
-                                       &syncCookie->ctxcsn[i], op->o_tmpmemctx );
-                               mod[1].sml_numvals++;
-                               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 );
-                       mod[1].sml_numvals++;
-                       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;
@@ -2694,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 );
@@ -2742,9 +2822,8 @@ syncrepl_updateCookie(
        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;
 }
@@ -2792,6 +2871,19 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
                        }
                }
 
+               /* 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 ( no == o ) {
@@ -2901,39 +2993,32 @@ dn_callback(
                        if ( dni->new_entry ) {
                                Modifications **modtail, **ml;
                                Attribute *old, *new;
+                               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 || attr_valfind( a,
-                                               SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
-                                               SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
-                                               SLAP_MR_VALUE_OF_SYNTAX,
-                                               &oldVal, NULL, 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;
@@ -2945,7 +3030,8 @@ dn_callback(
                                new = attr_find( dni->new_entry->e_attrs,
                                        slap_schema.si_ad_entryCSN );
                                if ( new && old ) {
-                                       int rc, 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;
                                        rc = memcmp( old->a_vals[0].bv_val,
@@ -3075,12 +3161,12 @@ nonpresent_callback(
                        }
 
                        if ( LogTest( LDAP_DEBUG_SYNC ) ) {
-                               char buf[sizeof("rid=999 not")];
+                               char buf[sizeof("rid=999 non")];
 
                                snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
-                                       present_uuid ? "got" : "not" );
+                                       present_uuid ? "" : "non" );
 
-                               Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s UUID %s, dn %s\n",
+                               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 );
                        }
 
@@ -3257,6 +3343,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                }
        
                /* 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 ) )
@@ -3264,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 );
@@ -3914,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
@@ -3941,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 {
@@ -3961,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 );
 
@@ -3977,9 +4064,10 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 
        ptr = buf;
        assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
-       ptr += snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
+       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 );
@@ -4037,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++ = ',';
@@ -4054,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 "=" );
@@ -4076,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 ) {
@@ -4145,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 );