]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
Plug mutex/rwlock leaks (destroy them)
[openldap] / servers / slapd / syncrepl.c
index 80b7c34b7f1827b173e65012894167a3e1c35984..b2f7cd3be65f1764f49c9b2220e6fe4a4cda56c6 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2009 The OpenLDAP Foundation.
+ * Copyright 2003-2010 The OpenLDAP Foundation.
  * Portions Copyright 2003 by IBM Corporation.
  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
  * All rights reserved.
@@ -44,8 +44,14 @@ typedef struct cookie_state {
        int cs_ref;
        struct berval *cs_vals;
        int *cs_sids;
-} cookie_state;
        
+       /* pending changes, not yet committed */
+       ldap_pvt_thread_mutex_t cs_pmutex;
+       int     cs_pnum;
+       struct berval *cs_pvals;
+       int *cs_psids;
+} cookie_state;
+
 #define        SYNCDATA_DEFAULT        0       /* entries are plain LDAP entries */
 #define        SYNCDATA_ACCESSLOG      1       /* entries are accesslog format */
 #define        SYNCDATA_CHANGELOG      2       /* entries are changelog format */
@@ -69,6 +75,7 @@ typedef struct syncinfo_s {
        struct berval           si_base;
        struct berval           si_logbase;
        struct berval           si_filterstr;
+       Filter                  *si_filter;
        struct berval           si_logfilterstr;
        struct berval           si_contextdn;
        int                     si_scope;
@@ -124,6 +131,8 @@ static int syncrepl_updateCookie(
                                        struct sync_cookie * );
 static struct berval * slap_uuidstr_from_normalized(
                                        struct berval *, struct berval *, void * );
+static int syncrepl_add_glue_ancestors(
+       Operation* op, Entry *e );
 
 /* callback functions */
 static int dn_callback( Operation *, SlapReply * );
@@ -762,7 +771,7 @@ do_syncrep2(
 
        Modifications   *modlist = NULL;
 
-       int                             match, m;
+       int                             match, m, punlock = -1;
 
        struct timeval *tout_p = NULL;
        struct timeval tout = { 0, 0 };
@@ -803,7 +812,7 @@ do_syncrep2(
                        ldap_get_entry_controls( si->si_ld, msg, &rctrls );
                        /* we can't work without the control */
                        if ( rctrls ) {
-                               LDAPControl **next;
+                               LDAPControl **next = NULL;
                                /* NOTE: make sure we use the right one;
                                 * a better approach would be to run thru
                                 * the whole list and take care of all */
@@ -845,8 +854,9 @@ do_syncrep2(
                        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 );
+                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+                                       si->si_ridtxt,
+                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
 
                                if ( !BER_BVISNULL( &cookie ) ) {
                                        ch_free( syncCookie.octet_str.bv_val );
@@ -857,16 +867,51 @@ do_syncrep2(
                                        slap_parse_sync_cookie( &syncCookie, NULL );
                                        if ( syncCookie.ctxcsn ) {
                                                int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
+                                               check_syncprov( op, si );
                                                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;
+                                                       if ( si->si_cookieState->cs_sids[i] == sid ) {
+                                                               if ( 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;
+                                                               }
+                                                               break;
+                                                       }
+                                               }
+                                               /* check pending CSNs too */
+                                               while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
+                                                       if ( slapd_shutdown ) {
+                                                               rc = -2;
                                                                goto done;
                                                        }
+                                                       if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
+                                                               ldap_pvt_thread_yield();
+                                               }
+                                               for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
+                                                       if ( si->si_cookieState->cs_psids[i] == sid ) {
+                                                               if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
+                                                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s\n",
+                                                                               si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
+                                                                       ldap_controls_free( rctrls );
+                                                                       rc = 0;
+                                                                       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
+                                                                       goto done;
+                                                               }
+                                                               ber_bvreplace( &si->si_cookieState->cs_pvals[i],
+                                                                       syncCookie.ctxcsn );
+                                                               break;
+                                                       }
+                                               }
+                                               /* new SID, add it */
+                                               if ( i == si->si_cookieState->cs_pnum ) {
+                                                       value_add( &si->si_cookieState->cs_pvals, syncCookie.ctxcsn );
+                                                       si->si_cookieState->cs_pnum++;
+                                                       si->si_cookieState->cs_psids = ch_realloc( si->si_cookieState->cs_psids, si->si_cookieState->cs_pnum * sizeof(int));
+                                                       si->si_cookieState->cs_psids[i] = sid;
                                                }
+                                               punlock = i;
                                        }
                                        op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
                                }
@@ -900,6 +945,22 @@ do_syncrep2(
                                        rc = syncrepl_updateCookie( si, op, &syncCookie );
                                }
                        }
+                       if ( punlock >= 0 ) {
+                               /* on failure, revert pending CSN */
+                               if ( rc != LDAP_SUCCESS ) {
+                                       int i;
+                                       for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
+                                               if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
+                                                       ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
+                                                               &si->si_cookieState->cs_vals[i] );
+                                                       break;
+                                               }
+                                       }
+                                       if ( i == si->si_cookieState->cs_num )
+                                               si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
+                               }
+                               ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
+                       }
                        ldap_controls_free( rctrls );
                        if ( modlist ) {
                                slap_mods_free( modlist, 1 );
@@ -939,7 +1000,7 @@ do_syncrep2(
                                        si->si_ridtxt, err, ldap_err2string( err ) );
                        }
                        if ( rctrls ) {
-                               LDAPControl **next;
+                               LDAPControl **next = NULL;
                                /* NOTE: make sure we use the right one;
                                 * a better approach would be to run thru
                                 * the whole list and take care of all */
@@ -965,8 +1026,9 @@ do_syncrep2(
                                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 );
+                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+                                               si->si_ridtxt, 
+                                               BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
 
                                        if ( !BER_BVISNULL( &cookie ) ) {
                                                ch_free( syncCookie.octet_str.bv_val );
@@ -1075,8 +1137,9 @@ do_syncrep2(
                                        {
                                                ber_scanf( ber, "m", &cookie );
 
-                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
-                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+                                                       si->si_ridtxt, 
+                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
 
                                                if ( !BER_BVISNULL( &cookie ) ) {
                                                        ch_free( syncCookie.octet_str.bv_val );
@@ -1111,8 +1174,9 @@ do_syncrep2(
                                        {
                                                ber_scanf( ber, "m", &cookie );
 
-                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
-                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+                                                       si->si_ridtxt,
+                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
 
                                                if ( !BER_BVISNULL( &cookie ) ) {
                                                        ch_free( syncCookie.octet_str.bv_val );
@@ -1306,6 +1370,8 @@ do_syncrepl(
 
        connection_fake_init( &conn, &opbuf, ctx );
        op = &opbuf.ob_op;
+       /* o_connids must be unique for slap_graduate_commit_csn */
+       op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
 
        op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
        be = si->si_be;
@@ -1349,6 +1415,11 @@ do_syncrepl(
                si->si_refreshDelete = 0;
                si->si_refreshPresent = 0;
 
+               if ( si->si_presentlist ) {
+                   avl_free( si->si_presentlist, ch_free );
+                   si->si_presentlist = NULL;
+               }
+
                /* use main DB when retrieving contextCSN */
                op->o_bd = si->si_wbe;
                op->o_dn = op->o_bd->be_rootdn;
@@ -1495,10 +1566,11 @@ static slap_verbmasks modops[] = {
        { BER_BVNULL, 0 }
 };
 
-static Modifications *
+static int
 syncrepl_accesslog_mods(
        syncinfo_t *si,
-       struct berval *vals
+       struct berval *vals,
+       struct Modifications **modres
 )
 {
        char *colon;
@@ -1507,7 +1579,7 @@ syncrepl_accesslog_mods(
        struct berval bv, bv2;
        short op;
        Modifications *mod = NULL, *modlist = NULL, **modtail;
-       int i;
+       int i, rc = 0;
 
        modtail = &modlist;
 
@@ -1524,7 +1596,13 @@ syncrepl_accesslog_mods(
                bv.bv_len = colon - bv.bv_val;
                if ( slap_bv2ad( &bv, &ad, &text ) ) {
                        /* Invalid */
-                       continue;
+                       Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
+                               "Invalid attribute %s, %s\n",
+                               si->si_ridtxt, bv.bv_val, text );
+                       slap_mods_free( modlist, 1 );
+                       modlist = NULL;
+                       rc = -1;
+                       break;
                }
 
                /* Ignore dynamically generated attrs */
@@ -1569,16 +1647,18 @@ syncrepl_accesslog_mods(
                        mod->sml_numvals++;
                }
        }
-       return modlist;
+       *modres = modlist;
+       return rc;
 }
 
-static Modifications *
+static int
 syncrepl_changelog_mods(
        syncinfo_t *si,
-       struct berval *vals
+       struct berval *vals,
+       struct Modifications **modres
 )
 {
-       return NULL;    /* FIXME */
+       return -1;      /* FIXME */
 }
 
 static int
@@ -1673,10 +1753,11 @@ syncrepl_message_to_op(
                } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
                        /* Parse attribute into modlist */
                        if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
-                               modlist = syncrepl_accesslog_mods( si, bvals );
+                               rc = syncrepl_accesslog_mods( si, bvals, &modlist );
                        } else {
-                               modlist = syncrepl_changelog_mods( si, bvals );
+                               rc = syncrepl_changelog_mods( si, bvals, &modlist );
                        }
+                       if ( rc ) goto done;
                } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
                        rdn = bvals[0];
                } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
@@ -2488,7 +2569,19 @@ retry_add:;
                                mod->sml_next = m2;
                        }
                        op->o_bd = si->si_wbe;
+retry_modrdn:;
                        rc = op->o_bd->be_modrdn( op, &rs_modify );
+
+                       /* NOTE: noSuchObject should result because the new superior
+                        * has not been added yet (ITS#6472) */
+                       if ( rc == LDAP_NO_SUCH_OBJECT && !BER_BVISNULL( op->orr_nnewSup )) {
+                               Operation op2 = *op;
+                               rc = syncrepl_add_glue_ancestors( &op2, entry );
+                               if ( rc == LDAP_SUCCESS ) {
+                                       goto retry_modrdn;
+                               }
+                       }
+               
                        op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
                        op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
 
@@ -2675,7 +2768,7 @@ syncrepl_del_nonpresent(
                op->ors_tlimit = SLAP_NO_LIMIT;
                op->ors_limit = NULL;
                op->ors_attrsonly = 0;
-               op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
+               op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
                /* In multimaster, updates can continue to arrive while
                 * we're searching. Limit the search result to entries
                 * older than our newest cookie CSN.
@@ -2814,15 +2907,15 @@ syncrepl_del_nonpresent(
        return;
 }
 
-int
-syncrepl_add_glue(
+static int
+syncrepl_add_glue_ancestors(
        Operation* op,
        Entry *e )
 {
        Backend *be = op->o_bd;
        slap_callback cb = { NULL };
        Attribute       *a;
-       int     rc;
+       int     rc = LDAP_SUCCESS;
        int suffrdns;
        int i;
        struct berval dn = BER_BVNULL;
@@ -2949,6 +3042,34 @@ syncrepl_add_glue(
                ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
        }
 
+       return rc;
+}
+
+int
+syncrepl_add_glue(
+       Operation* op,
+       Entry *e )
+{
+       slap_callback cb = { NULL };
+       int     rc;
+       Backend *be = op->o_bd;
+       SlapReply       rs_add = {REP_RESULT};
+
+       rc = syncrepl_add_glue_ancestors( op, e );
+       switch ( rc ) {
+       case LDAP_SUCCESS:
+       case LDAP_ALREADY_EXISTS:
+               break;
+
+       default:
+               return rc;
+       }
+
+       op->o_tag = LDAP_REQ_ADD;
+       op->o_callback = &cb;
+       cb.sc_response = null_callback;
+       cb.sc_private = NULL;
+
        op->o_req_dn = e->e_name;
        op->o_req_ndn = e->e_nname;
        op->ora_e = e;
@@ -2976,7 +3097,7 @@ syncrepl_updateCookie(
        Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
 #endif
 
-       int rc, i, j;
+       int rc, i, j, changed = 0;
        ber_len_t len;
 
        slap_callback cb = { NULL };
@@ -3018,6 +3139,7 @@ syncrepl_updateCookie(
                        if ( memcmp( syncCookie->ctxcsn[i].bv_val,
                                si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
                                mod.sml_values[j] = syncCookie->ctxcsn[i];
+                               changed = 1;
                                if ( BER_BVISNULL( &first ) ) {
                                        first = syncCookie->ctxcsn[i];
 
@@ -3040,10 +3162,11 @@ syncrepl_updateCookie(
                        {
                                first = syncCookie->ctxcsn[i];
                        }
+                       changed = 1;
                }
        }
        /* Should never happen, ITS#5065 */
-       if ( BER_BVISNULL( &first )) {
+       if ( BER_BVISNULL( &first ) || !changed ) {
                ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
                op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
                return 0;
@@ -3180,10 +3303,12 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
                 * Also use replace op if attr has no equality matching rule.
                 * (ITS#5781)
                 */
-               if ( nn && no < o &&
+               if ( ( nn || ( no > 0 && no < o ) ) &&
                        ( old->a_desc == slap_schema.si_ad_objectClass ||
-                        !old->a_desc->ad_type->sat_equality ))
+                        !old->a_desc->ad_type->sat_equality ) )
+               {
                        no = o;
+               }
 
                i = j;
                /* all old values were deleted, just use the replace op */
@@ -3709,6 +3834,9 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                if ( sie->si_filterstr.bv_val ) {
                        ch_free( sie->si_filterstr.bv_val );
                }
+               if ( sie->si_filter ) {
+                       filter_free( sie->si_filter );
+               }
                if ( sie->si_logfilterstr.bv_val ) {
                        ch_free( sie->si_logfilterstr.bv_val );
                }
@@ -3718,7 +3846,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                if ( sie->si_logbase.bv_val ) {
                        ch_free( sie->si_logbase.bv_val );
                }
-               if ( SLAP_SYNC_SUBENTRY( sie->si_be )) {
+               if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
                        ch_free( sie->si_contextdn.bv_val );
                }
                if ( sie->si_attrs ) {
@@ -3790,6 +3918,9 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                                ch_free( sie->si_cookieState->cs_sids );
                                ber_bvarray_free( sie->si_cookieState->cs_vals );
                                ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
+                               ch_free( sie->si_cookieState->cs_psids );
+                               ber_bvarray_free( sie->si_cookieState->cs_pvals );
+                               ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
                                ch_free( sie->si_cookieState );
                        }
                }
@@ -3973,10 +4104,10 @@ parse_syncrepl_line(
                                Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
                                return -1;
                        }
-                       if ( tmp > SLAP_SYNC_SID_MAX || tmp < 0 ) {
+                       if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
                                snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                        "Error: parse_syncrepl_line: "
-                                       "syncrepl id %d is out of range [0..4095]", tmp );
+                                       "syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
                                Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
                                return -1;
                        }
@@ -3988,6 +4119,10 @@ parse_syncrepl_line(
                {
                        val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
                        ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
+#ifdef HAVE_TLS
+                       if ( ldap_is_ldaps_url( val ))
+                               si->si_bindconf.sb_tls_do_init = 1;
+#endif
                        si->si_got |= GOT_PROVIDER;
                } else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
                                        STRLENOF( SCHEMASTR "=" ) ) )
@@ -4318,6 +4453,13 @@ parse_syncrepl_line(
                }
        }
 
+       si->si_filter = str2filter( si->si_filterstr.bv_val );
+       if ( si->si_filter == NULL ) {
+               Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n", 
+                       si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
+               return 1;
+       }
+
        return 0;
 }
 
@@ -4455,9 +4597,10 @@ add_syncrepl(
                return 1;
        } else {
                Debug( LDAP_DEBUG_CONFIG,
-                       "Config: ** successfully added syncrepl \"%s\"\n",
+                       "Config: ** successfully added syncrepl %s \"%s\"\n",
+                       si->si_ridtxt,
                        BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
-                       "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
+                       "(null)" : si->si_bindconf.sb_uri.bv_val, 0 );
                if ( c->be->be_syncinfo ) {
                        syncinfo_t *sip;
 
@@ -4469,6 +4612,7 @@ add_syncrepl(
                } else {
                        si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
                        ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
+                       ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
 
                        c->be->be_syncinfo = si;
                }
@@ -4500,7 +4644,7 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
        si->si_bindconf.sb_version = LDAP_VERSION3;
 
        ptr = buf;
-       assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
+       assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
        len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
                si->si_rid, si->si_bindconf.sb_uri.bv_val );
        if ( len >= sizeof( buf ) ) return;
@@ -4677,6 +4821,8 @@ syncrepl_config( ConfigArgs *c )
                                si = *sip;
                                if ( c->valx == -1 || i == c->valx ) {
                                        *sip = si->si_next;
+                                       si->si_ctype = -1;
+                                       si->si_next = NULL;
                                        /* 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.
@@ -4685,22 +4831,34 @@ syncrepl_config( ConfigArgs *c )
                                                if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
                                                        isrunning = 1;
                                                } else {
+                                                       /* There is no active thread, but we must still
+                                                        * ensure that no thread is (or will be) queued
+                                                        * while we removes the task.
+                                                        */
+                                                       struct re_s *re = si->si_re;
+                                                       si->si_re = NULL;
+
                                                        if ( si->si_conn ) {
-                                                               /* If there's a persistent connection, it may
-                                                                * already have a thread queued. We know it's
-                                                                * not active, so it must be pending and we
-                                                                * can simply cancel it now.
-                                                                */
-                                                               ldap_pvt_thread_pool_retract( &connection_pool,
-                                                                       si->si_re->routine, si->si_re );
+                                                               connection_client_stop( si->si_conn );
+                                                               si->si_conn = NULL;
                                                        }
+
+                                                       ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+                                                       if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
+                                                               ldap_pvt_runqueue_stoptask( &slapd_rq, re );
+                                                               isrunning = 1;
+                                                       }
+                                                       ldap_pvt_runqueue_remove( &slapd_rq, re );
+                                                       ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+                                                       if ( ldap_pvt_thread_pool_retract( &connection_pool,
+                                                                       re->routine, re ) > 0 )
+                                                               isrunning = 0;
+
                                                        ldap_pvt_thread_mutex_unlock( &si->si_mutex );
                                                }
                                        }
-                                       if ( isrunning ) {
-                                               si->si_ctype = -1;
-                                               si->si_next = NULL;
-                                       } else {
+                                       if ( !isrunning ) {
                                                syncinfo_free( si, 0 );
                                        }
                                        if ( i == c->valx )