]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
ITS#8789 avoid unnecessary writes of context entry
[openldap] / servers / slapd / syncrepl.c
index 23b638d24f0193048d8866305165aa4936d2577e..a0b87a9ec47be30a45b198d6b6ca3e487dd8044c 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2014 The OpenLDAP Foundation.
+ * Copyright 2003-2017 The OpenLDAP Foundation.
  * Portions Copyright 2003 by IBM Corporation.
  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
  * All rights reserved.
@@ -46,11 +46,13 @@ struct nonpresent_entry {
 
 typedef struct cookie_state {
        ldap_pvt_thread_mutex_t cs_mutex;
+       ldap_pvt_thread_cond_t cs_cond;
        struct berval *cs_vals;
        int *cs_sids;
        int     cs_num;
        int cs_age;
        int cs_ref;
+       int cs_updating;
 
        /* pending changes, not yet committed */
        ldap_pvt_thread_mutex_t cs_pmutex;
@@ -82,8 +84,9 @@ typedef struct syncinfo_s {
        struct berval           si_base;
        struct berval           si_logbase;
        struct berval           si_filterstr;
-       Filter                  *si_filter;
        struct berval           si_logfilterstr;
+       Filter                  *si_filter;
+       Filter                  *si_logfilter;
        struct berval           si_contextdn;
        int                     si_scope;
        int                     si_attrsonly;
@@ -110,12 +113,17 @@ typedef struct syncinfo_s {
        int                     si_refreshDelete;
        int                     si_refreshPresent;
        int                     si_refreshDone;
+       int                     si_refreshCount;
+       time_t          si_refreshBeg;
+       time_t          si_refreshEnd;
+       OpExtra         *si_refreshTxn;
        int                     si_syncdata;
        int                     si_logstate;
        int                     si_lazyCommit;
        int                     si_got;
        int                     si_strict_refresh;      /* stop listening during fallback refresh */
        int                     si_too_old;
+       int                     si_has_syncprov;
        ber_int_t       si_msgid;
        Avlnode                 *si_presentlist;
        LDAP                    *si_ld;
@@ -145,7 +153,7 @@ static int syncrepl_entry(
                                        struct berval *cookieCSN );
 static int syncrepl_updateCookie(
                                        syncinfo_t *, Operation *,
-                                       struct sync_cookie * );
+                                       struct sync_cookie *, int save );
 static struct berval * slap_uuidstr_from_normalized(
                                        struct berval *, struct berval *, void * );
 static int syncrepl_add_glue_ancestors(
@@ -157,7 +165,6 @@ static int syncrepl_op_modify( Operation *op, SlapReply *rs );
 /* callback functions */
 static int dn_callback( Operation *, SlapReply * );
 static int nonpresent_callback( Operation *, SlapReply * );
-static int null_callback( Operation *, SlapReply * );
 
 static AttributeDescription *sync_descs[4];
 
@@ -171,6 +178,7 @@ typedef struct logschema {
        struct berval ls_newRdn;
        struct berval ls_delRdn;
        struct berval ls_newSup;
+       struct berval ls_controls;
 } logschema;
 
 static logschema changelog_sc = {
@@ -179,7 +187,8 @@ static logschema changelog_sc = {
        BER_BVC("changes"),
        BER_BVC("newRDN"),
        BER_BVC("deleteOldRDN"),
-       BER_BVC("newSuperior")
+       BER_BVC("newSuperior"),
+       BER_BVC("controls")
 };
 
 static logschema accesslog_sc = {
@@ -188,7 +197,8 @@ static logschema accesslog_sc = {
        BER_BVC("reqMod"),
        BER_BVC("reqNewRDN"),
        BER_BVC("reqDeleteOldRDN"),
-       BER_BVC("reqNewSuperior")
+       BER_BVC("reqNewSuperior"),
+       BER_BVC("reqControls")
 };
 
 static const char *
@@ -404,7 +414,7 @@ ldap_sync_search(
        int rc;
        int rhint;
        char *base;
-       char **attrs, *lattrs[8];
+       char **attrs, *lattrs[9];
        char *filter;
        int attrsonly;
        int scope;
@@ -433,8 +443,9 @@ ldap_sync_search(
                lattrs[3] = ls->ls_newRdn.bv_val;
                lattrs[4] = ls->ls_delRdn.bv_val;
                lattrs[5] = ls->ls_newSup.bv_val;
-               lattrs[6] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
-               lattrs[7] = NULL;
+               lattrs[6] = ls->ls_controls.bv_val;
+               lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
+               lattrs[8] = NULL;
 
                rhint = 0;
                base = si->si_logbase.bv_val;
@@ -553,6 +564,7 @@ check_syncprov(
                        ber_bvarray_free( a.a_nvals );
                }
                ber_bvarray_free( a.a_vals );
+               si->si_has_syncprov = 1;
        }
        /* See if the cookieState has changed due to anything outside
         * this particular consumer. That includes other consumers in
@@ -717,6 +729,8 @@ do_syncrep1(
                                        si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
                        }
                        ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+                       /* Also look in syncprov overlay, if it was already active */
+                       check_syncprov( op, si );
                }
 
                ch_free( si->si_syncCookie.octet_str.bv_val );
@@ -736,6 +750,11 @@ do_syncrep1(
        }
 
        si->si_refreshDone = 0;
+       si->si_refreshBeg = slap_get_time();
+       si->si_refreshCount = 0;
+       si->si_refreshTxn = NULL;
+       Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s starting refresh\n",
+               si->si_ridtxt, 0, 0 );
 
        rc = ldap_sync_search( si, op->o_tmpmemctx );
 
@@ -935,6 +954,10 @@ do_syncrep2(
                                                check_syncprov( op, si );
                                                ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
                                                for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+#ifdef CHATTY_SYNCLOG
+                                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
+                                                               si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
+#endif
                                                        /* new SID */
                                                        if ( sid < si->si_cookieState->cs_sids[i] )
                                                                break;
@@ -1010,7 +1033,7 @@ do_syncrep2(
                                if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
                                        syncCookie.ctxcsn )
                                {
-                                       rc = syncrepl_updateCookie( si, op, &syncCookie );
+                                       rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
                                } else switch ( rc ) {
                                        case LDAP_ALREADY_EXISTS:
                                        case LDAP_NO_SUCH_OBJECT:
@@ -1038,7 +1061,7 @@ do_syncrep2(
                                        syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
                                        syncCookie.ctxcsn )
                                {
-                                       rc = syncrepl_updateCookie( si, op, &syncCookie );
+                                       rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
                                }
                        }
                        if ( punlock >= 0 ) {
@@ -1184,8 +1207,15 @@ do_syncrep2(
                        }
                        if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
                        {
-                               rc = syncrepl_updateCookie( si, op, &syncCookie );
+                               rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
+                       }
+                       if ( si->si_refreshCount ) {
+                               LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+                               op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+                               si->si_refreshCount = 0;
+                               si->si_refreshTxn = NULL;
                        }
+                       si->si_refreshEnd = slap_get_time();
                        if ( err == LDAP_SUCCESS
                                && si->si_logstate == SYNCLOG_FALLBACK ) {
                                si->si_logstate = SYNCLOG_LOGGING;
@@ -1267,6 +1297,17 @@ do_syncrep2(
                                        {
                                                si->si_refreshDone = 1;
                                        }
+                                       if ( si->si_refreshDone ) {
+                                               if ( si->si_refreshCount ) {
+                                                       LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+                                                       op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+                                                       si->si_refreshCount = 0;
+                                                       si->si_refreshTxn = NULL;
+                                               }
+                                               si->si_refreshEnd = slap_get_time();
+       Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s finished refresh\n",
+               si->si_ridtxt, 0, 0 );
+                                       }
                                        ber_scanf( ber, /*"{"*/ "}" );
                                        if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
                                                si->si_refreshDone )
@@ -1356,7 +1397,7 @@ do_syncrep2(
 
                                        if ( syncCookie.ctxcsn )
                                        {
-                                               rc = syncrepl_updateCookie( si, op, &syncCookie);
+                                               rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
                                        }
                                        if ( si->si_presentlist ) {
                                                presentlist_free( si->si_presentlist );
@@ -1397,6 +1438,12 @@ do_syncrep2(
                if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
                        slap_sync_cookie_free( &syncCookie, 0 );
                        slap_sync_cookie_free( &syncCookie_req, 0 );
+                       if ( si->si_refreshCount ) {
+                               LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+                               op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+                               si->si_refreshCount = 0;
+                               si->si_refreshTxn = NULL;
+                       }
                        return SYNC_PAUSED;
                }
        }
@@ -1757,6 +1804,11 @@ syncrepl_accesslog_mods(
                if ( !colon ) {
                        /* Invalid */
                        continue;
+               } else if ( colon == bv.bv_val ) {
+                       /* ITS#6545: An empty attribute signals that a new mod
+                        * is about to start */
+                       mod = NULL;
+                       continue;
                }
 
                bv.bv_len = colon - bv.bv_val;
@@ -2065,6 +2117,33 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
        if ( !mod )
                return SLAP_CB_CONTINUE;
 
+       {
+               int i, sid;
+               sid = slap_parse_csn_sid( &mod->sml_nvalues[0] );
+               ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+               for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+#ifdef CHATTY_SYNCLOG
+                       Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s CSN for sid %d: %s\n",
+                               si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
+#endif
+                       /* new SID */
+                       if ( sid < si->si_cookieState->cs_sids[i] )
+                               break;
+                       if ( si->si_cookieState->cs_sids[i] == sid ) {
+                               if ( ber_bvcmp( &mod->sml_nvalues[0], &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+                                       Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s entryCSN too old, ignoring %s (%s)\n",
+                                               si->si_ridtxt, mod->sml_nvalues[0].bv_val, op->o_req_dn.bv_val );
+                                       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+                                       slap_graduate_commit_csn( op );
+                                       /* tell accesslog this was a failure */
+                                       rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
+                                       return LDAP_SUCCESS;
+                               }
+                       }
+               }
+               ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+       }
+
        rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
        if ( rc == 0 ) {
                Attribute *a;
@@ -2078,6 +2157,7 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
        }
        /* equal? Should never happen */
        if ( match == 0 ) {
+               slap_graduate_commit_csn( op );
                /* tell accesslog this was a failure */
                rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
                return LDAP_SUCCESS;
@@ -2118,14 +2198,13 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
        if ( match < 0 ) {
                Operation op2 = *op;
                AttributeName an[2];
-               const char *text;
                struct berval bv;
-               char *ptr;
-               Modifications *ml;
-               int size, rc;
+               int size;
                SlapReply rs1 = {0};
                resolve_ctxt rx;
                slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
+        Filter lf[3] = {0};
+        AttributeAssertion aa[2] = {0};
 
                rx.rx_si = si;
                rx.rx_mods = newlist;
@@ -2153,7 +2232,21 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
                        "(&(entryCSN>=%s)(reqDN=%s)%s)",
                        bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
-               op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
+
+        lf[0].f_choice = LDAP_FILTER_AND;
+        lf[0].f_and = lf+1;
+        lf[1].f_choice = LDAP_FILTER_GE;
+        lf[1].f_ava = aa;
+        lf[1].f_av_desc = slap_schema.si_ad_entryCSN;
+        lf[1].f_av_value = bv;
+        lf[1].f_next = lf+2;
+        lf[2].f_choice = LDAP_FILTER_EQUALITY;
+        lf[2].f_ava = aa+1;
+        lf[2].f_av_desc = ad_reqDN;
+        lf[2].f_av_value = op->o_req_ndn;
+        lf[2].f_next = si->si_logfilter;
+
+               op2.ors_filter = lf;
 
                op2.o_callback = &cb;
                op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
@@ -2171,6 +2264,7 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
                sc->sc_private = mx;
                sc->sc_next = op->o_callback;
                sc->sc_cleanup = NULL;
+               sc->sc_writewait = NULL;
                op->o_callback = sc;
                op->orm_no_opattrs = 1;
                mx->mx_orig = op->orm_modlist;
@@ -2192,6 +2286,34 @@ syncrepl_op_modify( Operation *op, SlapReply *rs )
        return SLAP_CB_CONTINUE;
 }
 
+static int
+syncrepl_null_callback(
+       Operation *op,
+       SlapReply *rs )
+{
+       /* If we're not the last callback in the chain, move to the end */
+       if ( op->o_callback->sc_next ) {
+               slap_callback **sc, *s1;
+               s1 = op->o_callback;
+               op->o_callback = op->o_callback->sc_next;
+               for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) ;
+               *sc = s1;
+               s1->sc_next = NULL;
+               return SLAP_CB_CONTINUE;
+       }
+       if ( rs->sr_err != LDAP_SUCCESS &&
+               rs->sr_err != LDAP_REFERRAL &&
+               rs->sr_err != LDAP_ALREADY_EXISTS &&
+               rs->sr_err != LDAP_NO_SUCH_OBJECT &&
+               rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
+       {
+               Debug( LDAP_DEBUG_ANY,
+                       "syncrepl_null_callback : error code 0x%x\n",
+                       rs->sr_err, 0, 0 );
+       }
+       return LDAP_SUCCESS;
+}
+
 static int
 syncrepl_message_to_op(
        syncinfo_t      *si,
@@ -2203,7 +2325,7 @@ syncrepl_message_to_op(
        Modifications   *modlist = NULL;
        logschema *ls;
        SlapReply rs = { REP_RESULT };
-       slap_callback cb = { NULL, null_callback, NULL, NULL };
+       slap_callback cb = { NULL, syncrepl_null_callback, NULL, NULL };
 
        const char      *text;
        char txtbuf[SLAP_TEXT_BUFLEN];
@@ -2297,6 +2419,22 @@ syncrepl_message_to_op(
                        }
                } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
                        sup = bvals[0];
+               } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_controls ) ) {
+                       int i;
+                       struct berval rel_ctrl_bv;
+
+                       (void)ber_str2bv( "{" LDAP_CONTROL_RELAX, 0, 0, &rel_ctrl_bv );
+                       for ( i = 0; bvals[i].bv_val; i++ ) {
+                               struct berval cbv, tmp;
+
+                               ber_bvchr_post( &cbv, &bvals[i], '}' );
+                               ber_bvchr_post( &tmp, &cbv, '{' );
+                               ber_bvchr_pre( &cbv, &tmp, ' ' );
+                               if ( cbv.bv_len == tmp.bv_len )         /* control w/o value */
+                                       ber_bvchr_pre( &cbv, &tmp, '}' );
+                               if ( !ber_bvcmp( &cbv, &rel_ctrl_bv ) )
+                                       op->o_relax = SLAP_CONTROL_CRITICAL;
+                       }
                } else if ( !ber_bvstrcasecmp( &bv,
                        &slap_schema.si_ad_entryCSN->ad_cname ) )
                {
@@ -2315,6 +2453,9 @@ syncrepl_message_to_op(
        op->o_callback = &cb;
        slap_op_time( &op->o_time, &op->o_tincr );
 
+       Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s tid %x\n",
+               si->si_ridtxt, op->o_tid, 0 );
+
        switch( op->o_tag ) {
        case LDAP_REQ_ADD:
        case LDAP_REQ_MODIFY:
@@ -2751,6 +2892,9 @@ presentlist_find(
        Avlnode **a2 = (Avlnode **)av;
        unsigned short s;
 
+       if (!av)
+               return NULL;
+
        memcpy(&s, val->bv_val, 2);
        return avl_find( a2[s], val->bv_val+2, syncuuid_cmp );
 #else
@@ -2819,8 +2963,8 @@ syncrepl_entry(
        int     freecsn = 1;
 
        Debug( LDAP_DEBUG_SYNC,
-               "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s)\n",
-               si->si_ridtxt, syncrepl_state2str( syncstate ), 0 );
+               "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) tid %x\n",
+               si->si_ridtxt, syncrepl_state2str( syncstate ), op->o_tid );
 
        if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
                if ( !si->si_refreshPresent && !si->si_refreshDone ) {
@@ -2915,7 +3059,7 @@ syncrepl_entry(
                slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
        }
 
-       cb.sc_response = null_callback;
+       cb.sc_response = syncrepl_null_callback;
        cb.sc_private = si;
 
        if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
@@ -2933,8 +3077,22 @@ syncrepl_entry(
                slap_queue_csn( op, syncCSN );
        }
 
-       if ( !si->si_refreshDone && si->si_lazyCommit )
-               op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
+       if ( !si->si_refreshDone ) {
+               if ( si->si_lazyCommit )
+                       op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
+               if ( si->si_refreshCount == 500 ) {
+                       LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+                       op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+                       si->si_refreshCount = 0;
+                       si->si_refreshTxn = NULL;
+               }
+               if ( op->o_bd->bd_info->bi_op_txn ) {
+                       if ( !si->si_refreshCount ) {
+                               op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_BEGIN, &si->si_refreshTxn );
+                       }
+                       si->si_refreshCount++;
+               }
+       }
 
        slap_op_time( &op->o_time, &op->o_tincr );
        switch ( syncstate ) {
@@ -3321,7 +3479,7 @@ retry_modrdn:;
                                op->o_delete_glue_parent = 0;
                                if ( !be_issuffix( be, &op->o_req_ndn ) ) {
                                        slap_callback cb = { NULL };
-                                       cb.sc_response = slap_null_cb;
+                                       cb.sc_response = syncrepl_null_callback;
                                        dnParent( &op->o_req_ndn, &pdn );
                                        op->o_req_dn = pdn;
                                        op->o_req_ndn = pdn;
@@ -3519,7 +3677,7 @@ syncrepl_del_nonpresent(
                        np_list = LDAP_LIST_NEXT( np_list, npe_link );
                        op->o_tag = LDAP_REQ_DELETE;
                        op->o_callback = &cb;
-                       cb.sc_response = null_callback;
+                       cb.sc_response = syncrepl_null_callback;
                        cb.sc_private = si;
                        op->o_req_dn = *np_prev->npe_name;
                        op->o_req_ndn = *np_prev->npe_nname;
@@ -3561,7 +3719,7 @@ syncrepl_del_nonpresent(
                                op->o_delete_glue_parent = 0;
                                if ( !be_issuffix( be, &op->o_req_ndn ) ) {
                                        slap_callback cb = { NULL };
-                                       cb.sc_response = slap_null_cb;
+                                       cb.sc_response = syncrepl_null_callback;
                                        dnParent( &op->o_req_ndn, &pdn );
                                        op->o_req_dn = pdn;
                                        op->o_req_ndn = pdn;
@@ -3614,7 +3772,7 @@ syncrepl_add_glue_ancestors(
 
        op->o_tag = LDAP_REQ_ADD;
        op->o_callback = &cb;
-       cb.sc_response = null_callback;
+       cb.sc_response = syncrepl_null_callback;
        cb.sc_private = NULL;
 
        dn = e->e_name;
@@ -3756,7 +3914,7 @@ syncrepl_add_glue(
 
        op->o_tag = LDAP_REQ_ADD;
        op->o_callback = &cb;
-       cb.sc_response = null_callback;
+       cb.sc_response = syncrepl_null_callback;
        cb.sc_private = NULL;
 
        op->o_req_dn = e->e_name;
@@ -3777,7 +3935,8 @@ static int
 syncrepl_updateCookie(
        syncinfo_t *si,
        Operation *op,
-       struct sync_cookie *syncCookie )
+       struct sync_cookie *syncCookie,
+       int save )
 {
        Backend *be = op->o_bd;
        Modifications mod;
@@ -3801,6 +3960,8 @@ syncrepl_updateCookie(
        mod.sml_next = NULL;
 
        ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+       while ( si->si_cookieState->cs_updating )
+               ldap_pvt_thread_cond_wait( &si->si_cookieState->cs_cond, &si->si_cookieState->cs_mutex );
 
 #ifdef CHECK_CSN
        for ( i=0; i<syncCookie->numcsns; i++ ) {
@@ -3863,44 +4024,56 @@ syncrepl_updateCookie(
                ch_free( sc.sids );
                return 0;
        }
-       op->o_bd = si->si_wbe;
-       slap_queue_csn( op, &first );
 
-       op->o_tag = LDAP_REQ_MODIFY;
+       si->si_cookieState->cs_updating = 1;
+       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+
+       if ( save || !si->si_has_syncprov ) {
+               op->o_bd = si->si_wbe;
+               slap_queue_csn( op, &first );
 
-       cb.sc_response = null_callback;
-       cb.sc_private = si;
+               op->o_tag = LDAP_REQ_MODIFY;
 
-       op->o_callback = &cb;
-       op->o_req_dn = si->si_contextdn;
-       op->o_req_ndn = si->si_contextdn;
+               cb.sc_response = syncrepl_null_callback;
+               cb.sc_private = si;
 
-       /* update contextCSN */
-       op->o_dont_replicate = 1;
+               op->o_callback = &cb;
+               op->o_req_dn = si->si_contextdn;
+               op->o_req_ndn = si->si_contextdn;
 
-       mod.sml_numvals = sc.numcsns;
-       mod.sml_values = sc.ctxcsn;
+               /* update contextCSN */
+               op->o_dont_replicate = 1;
 
-       op->orm_modlist = &mod;
-       op->orm_no_opattrs = 1;
-       rc = op->o_bd->be_modify( op, &rs_modify );
+               mod.sml_numvals = sc.numcsns;
+               mod.sml_values = sc.ctxcsn;
 
-       if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
-               SLAP_SYNC_SUBENTRY( op->o_bd )) {
-               const char      *text;
-               char txtbuf[SLAP_TEXT_BUFLEN];
-               size_t textlen = sizeof txtbuf;
-               Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
-               rs_reinit( &rs_modify, REP_RESULT );
-               rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
-               op->ora_e = e;
-               rc = op->o_bd->be_add( op, &rs_modify );
-               if ( e == op->ora_e )
-                       be_entry_release_w( op, op->ora_e );
+               op->orm_modlist = &mod;
+               op->orm_no_opattrs = 1;
+               rc = op->o_bd->be_modify( op, &rs_modify );
+
+               if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
+                       SLAP_SYNC_SUBENTRY( op->o_bd )) {
+                       const char      *text;
+                       char txtbuf[SLAP_TEXT_BUFLEN];
+                       size_t textlen = sizeof txtbuf;
+                       Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
+                       rs_reinit( &rs_modify, REP_RESULT );
+                       rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
+                       op->ora_e = e;
+                       rc = op->o_bd->be_add( op, &rs_modify );
+                       if ( e == op->ora_e )
+                               be_entry_release_w( op, op->ora_e );
+               }
+
+               op->orm_no_opattrs = 0;
+               op->o_dont_replicate = 0;
+       } else {
+               rc = 0;
        }
 
        op->orm_no_opattrs = 0;
        op->o_dont_replicate = 0;
+       ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
 
        if ( rs_modify.sr_err == LDAP_SUCCESS ) {
                slap_sync_cookie_free( &si->si_syncCookie, 0 );
@@ -3926,12 +4099,6 @@ syncrepl_updateCookie(
                ch_free( sc.sids );
                ber_bvarray_free( sc.ctxcsn );
        }
-       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
-
-       op->o_bd = be;
-       op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
-       BER_BVZERO( &op->o_csn );
-       if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
 
 #ifdef CHECK_CSN
        for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
@@ -3939,6 +4106,16 @@ syncrepl_updateCookie(
        }
 #endif
 
+       si->si_cookieState->cs_updating = 0;
+       ldap_pvt_thread_cond_broadcast( &si->si_cookieState->cs_cond );
+       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+
+       op->o_bd = be;
+       if ( op->o_csn.bv_val )
+               op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
+       BER_BVZERO( &op->o_csn );
+       if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
+
        return rc;
 }
 
@@ -4360,24 +4537,6 @@ nonpresent_callback(
        return LDAP_SUCCESS;
 }
 
-static int
-null_callback(
-       Operation*      op,
-       SlapReply*      rs )
-{
-       if ( rs->sr_err != LDAP_SUCCESS &&
-               rs->sr_err != LDAP_REFERRAL &&
-               rs->sr_err != LDAP_ALREADY_EXISTS &&
-               rs->sr_err != LDAP_NO_SUCH_OBJECT &&
-               rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
-       {
-               Debug( LDAP_DEBUG_ANY,
-                       "null_callback : error code 0x%x\n",
-                       rs->sr_err, 0, 0 );
-       }
-       return LDAP_SUCCESS;
-}
-
 static struct berval *
 slap_uuidstr_from_normalized(
        struct berval* uuidstr,
@@ -4534,6 +4693,9 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                if ( sie->si_logfilterstr.bv_val ) {
                        ch_free( sie->si_logfilterstr.bv_val );
                }
+               if ( sie->si_logfilter ) {
+                       filter_free( sie->si_logfilter );
+               }
                if ( sie->si_base.bv_val ) {
                        ch_free( sie->si_base.bv_val );
                }
@@ -4611,6 +4773,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                        if ( !sie->si_cookieState->cs_ref ) {
                                ch_free( sie->si_cookieState->cs_sids );
                                ber_bvarray_free( sie->si_cookieState->cs_vals );
+                               ldap_pvt_thread_cond_destroy( &sie->si_cookieState->cs_cond );
                                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 );
@@ -4687,11 +4850,11 @@ config_suffixm( ConfigArgs *c, syncinfo_t *si )
 #define LOGFILTERSTR   "logfilter"
 #define SUFFIXMSTR             "suffixmassage"
 #define        STRICT_REFRESH  "strictrefresh"
+#define LAZY_COMMIT            "lazycommit"
 
 /* FIXME: undocumented */
 #define EXATTRSSTR             "exattrs"
 #define MANAGEDSAITSTR         "manageDSAit"
-#define LAZY_COMMIT            "lazycommit"
 
 /* mandatory */
 enum {
@@ -5255,6 +5418,15 @@ parse_syncrepl_line(
                return 1;
        }
 
+       if ( si->si_got & GOT_LOGFILTER ) {
+               si->si_logfilter = str2filter( si->si_logfilterstr.bv_val );
+               if ( si->si_logfilter == NULL ) {
+                       Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse logfilter=\"%s\"\n", 
+                               si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_logfilterstr.bv_val );
+                       return 1;
+               }
+       }
+
        return 0;
 }
 
@@ -5408,6 +5580,7 @@ add_syncrepl(
                        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 );
+                       ldap_pvt_thread_cond_init( &si->si_cookieState->cs_cond );
 
                        c->be->be_syncinfo = si;
                }
@@ -5636,7 +5809,7 @@ syncrepl_config( ConfigArgs *c )
                                         * happen when running on the cn=config DB.
                                         */
                                        if ( si->si_re ) {
-                                               if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
+                                               if ( si->si_be == c->be || ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
                                                        isrunning = 1;
                                                } else {
                                                        /* There is no active thread, but we must still
@@ -5656,8 +5829,7 @@ syncrepl_config( ConfigArgs *c )
                                                                ldap_pvt_runqueue_stoptask( &slapd_rq, re );
                                                                isrunning = 1;
                                                        }
-                                                       if ( ldap_pvt_thread_pool_retract( &connection_pool,
-                                                                       re->routine, re ) > 0 )
+                                                       if ( ldap_pvt_thread_pool_retract( re->pool_cookie ) > 0 )
                                                                isrunning = 0;
 
                                                        ldap_pvt_runqueue_remove( &slapd_rq, re );