--- servers/slapd/overlays/syncprov.c 2008/03/19 23:31:42 1.223 +++ servers/slapd/overlays/syncprov.c 2008/05/29 21:48:35 1.240 @@ -1,4 +1,4 @@ -/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.222 2008/03/19 23:26:14 hyc Exp $ */ +/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.238 2008/05/28 00:46:35 hyc Exp $ */ /* syncprov.c - syncrepl provider */ /* This work is part of OpenLDAP Software . * @@ -404,7 +404,6 @@ syncprov_findbase( Operation *op, fbase_ slap_callback cb = {0}; Operation fop; SlapReply frs = { REP_RESULT }; - BackendInfo *bi; int rc; fc->fss->s_flags ^= PS_FIND_BASE; @@ -412,11 +411,10 @@ syncprov_findbase( Operation *op, fbase_ fop = *fc->fss->s_op; + fop.o_bd = fop.o_bd->bd_self; fop.o_hdr = op->o_hdr; - fop.o_bd = op->o_bd; fop.o_time = op->o_time; fop.o_tincr = op->o_tincr; - bi = op->o_bd->bd_info; cb.sc_response = findbase_cb; cb.sc_private = fc; @@ -434,8 +432,7 @@ syncprov_findbase( Operation *op, fbase_ fop.ors_filter = &generic_filter; fop.ors_filterstr = generic_filterstr; - rc = overlay_op_walk( &fop, &frs, op_search, on->on_info, on ); - op->o_bd->bd_info = bi; + rc = fop.o_bd->be_search( &fop, &frs ); } else { ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); fc->fbase = 1; @@ -500,7 +497,8 @@ findmax_cb( Operation *op, SlapReply *rs Attribute *a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ); - if ( a && ber_bvcmp( &a->a_vals[0], maxcsn ) > 0 ) { + if ( a && ber_bvcmp( &a->a_vals[0], maxcsn ) > 0 && + slap_parse_csn_sid( &a->a_vals[0] ) == slap_serverID ) { maxcsn->bv_len = a->a_vals[0].bv_len; strcpy( maxcsn->bv_val, a->a_vals[0].bv_val ); } @@ -590,7 +588,7 @@ syncprov_findcsn( Operation *op, find_cs sync_control *srs = NULL; struct slap_limits_set fc_limits; int i, rc = LDAP_SUCCESS, findcsn_retry = 1; - int maxid = 0; + int maxid; if ( mode != FIND_MAXCSN ) { srs = op->o_controls[slap_cids.sc_LDAPsync]; @@ -616,14 +614,20 @@ again: switch( mode ) { case FIND_MAXCSN: cf.f_choice = LDAP_FILTER_GE; - cf.f_av_value = si->si_ctxcsn[0]; - /* If there are multiple CSNs, use the largest */ - for ( i=1; isi_numcsns; i++) { - if ( ber_bvcmp( &cf.f_av_value, &si->si_ctxcsn[i] ) < 0 ) { - cf.f_av_value = si->si_ctxcsn[i]; + /* If there are multiple CSNs, use the one with our serverID */ + for ( i=0; isi_numcsns; i++) { + if ( slap_serverID == si->si_sids[i] ) { maxid = i; + break; } } + if ( i == si->si_numcsns ) { + /* No match: this is multimaster, and none of the content in the DB + * originated locally. Treat like no CSN. + */ + return LDAP_NO_SUCH_OBJECT; + } + cf.f_av_value = si->si_ctxcsn[maxid]; fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ), "(entryCSN>=%s)", cf.f_av_value.bv_val ); if ( fop.ors_filterstr.bv_len < 0 || fop.ors_filterstr.bv_len >= sizeof( buf ) ) { @@ -696,10 +700,7 @@ again: break; } - if ( on->on_next ) - fop.o_bd->bd_info = (BackendInfo *)on->on_next; - else - fop.o_bd->bd_info = on->on_info->oi_orig; + fop.o_bd->bd_info = (BackendInfo *)on->on_info; fop.o_bd->be_search( &fop, &frs ); fop.o_bd->bd_info = (BackendInfo *)on; @@ -740,6 +741,13 @@ syncprov_free_syncop( syncops *so ) ldap_pvt_thread_mutex_unlock( &so->s_mutex ); return; } + if ( so->s_qtask ) { + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + if ( ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) ) + ldap_pvt_runqueue_stoptask( &slapd_rq, so->s_qtask ); + ldap_pvt_runqueue_remove( &slapd_rq, so->s_qtask ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + } ldap_pvt_thread_mutex_unlock( &so->s_mutex ); if ( so->s_flags & PS_IS_DETACHED ) { filter_free( so->s_op->ors_filter ); @@ -1172,10 +1180,14 @@ syncprov_matchops( Operation *op, opcook for (ss = si->si_ops, sprev = (syncops *)&si->si_ops; ss; sprev = ss, ss=snext) { + Operation op2; syncmatches *sm; int found = 0; snext = ss->s_next; + if ( ss->s_op->o_abandon ) + continue; + /* validate base */ fc.fss = ss; fc.fbase = 0; @@ -1216,8 +1228,14 @@ syncprov_matchops( Operation *op, opcook } } + if ( fc.fscope ) { + op2 = *ss->s_op; + op2.o_hdr = op->o_hdr; + op2.o_extra = op->o_extra; + } + /* check if current o_req_dn is in scope and matches filter */ - if ( fc.fscope && test_filter( ss->s_op, e, ss->s_op->ors_filter ) == + if ( fc.fscope && test_filter( &op2, e, ss->s_op->ors_filter ) == LDAP_COMPARE_TRUE ) { if ( saveit ) { sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx ); @@ -1531,10 +1549,7 @@ syncprov_playlog( Operation *op, SlapRep fop.ors_filter = ⁡ cb.sc_response = playlog_cb; - if ( on->on_next ) - fop.o_bd->bd_info = (BackendInfo *)on->on_next; - else - fop.o_bd->bd_info = on->on_info->oi_orig; + fop.o_bd->bd_info = (BackendInfo *)on->on_info; for ( i=ndel; isr_state.rid, - srs->sr_state.sid ); + if ( delcsn[0].bv_len ) { + slap_compose_sync_cookie( op, &cookie, delcsn, srs->sr_state.rid, + srs->sr_state.sid ); + } Debug( LDAP_DEBUG_SYNC, "syncprov_playlog: cookie=%s\n", cookie.bv_val, 0, 0 ); uuids[ndel].bv_val = NULL; - syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, &cookie, 0, uuids, 1 ); + syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, + delcsn[0].bv_len ? &cookie : NULL, 0, uuids, 1 ); op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); } op->o_tmpfree( uuids, op->o_tmpmemctx ); @@ -1585,6 +1603,17 @@ syncprov_op_response( Operation *op, Sla cbuf[0] = '\0'; ldap_pvt_thread_rdwr_wlock( &si->si_csn_rwlock ); slap_get_commit_csn( op, &maxcsn ); + if ( BER_BVISNULL( &maxcsn ) && SLAP_GLUE_SUBORDINATE( op->o_bd )) { + /* syncrepl queues the CSN values in the db where + * it is configured , not where the changes are made. + * So look for a value in the glue db if we didn't + * find any in this db. + */ + BackendDB *be = op->o_bd; + op->o_bd = select_backend( &be->be_nsuffix[0], 1); + slap_get_commit_csn( op, &maxcsn ); + op->o_bd = be; + } if ( !BER_BVISNULL( &maxcsn ) ) { int i, sid; strcpy( cbuf, maxcsn.bv_val ); @@ -1605,6 +1634,10 @@ syncprov_op_response( Operation *op, Sla sizeof(int)); si->si_sids[i] = sid; } + } else { + /* internal ops that aren't meant to be replicated */ + ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); + return SLAP_CB_CONTINUE; } /* Don't do any processing for consumer contextCSN updates */ @@ -1967,6 +2000,7 @@ syncprov_search_response( Operation *op, { searchstate *ss = op->o_callback->sc_private; slap_overinst *on = ss->ss_on; + syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; sync_control *srs = op->o_controls[slap_cids.sc_LDAPsync]; if ( rs->sr_type == REP_SEARCH || rs->sr_type == REP_SEARCHREF ) { @@ -2032,8 +2066,16 @@ syncprov_search_response( Operation *op, rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2, op->o_tmpmemctx ); rs->sr_ctrls[1] = NULL; - rs->sr_err = syncprov_state_ctrl( op, rs, rs->sr_entry, - LDAP_SYNC_ADD, rs->sr_ctrls, 0, 0, NULL ); + /* If we're in delta-sync mode, always send a cookie */ + if ( si->si_nopres && si->si_usehint && a ) { + struct berval cookie; + slap_compose_sync_cookie( op, &cookie, a->a_nvals, srs->sr_state.rid, srs->sr_state.sid ); + rs->sr_err = syncprov_state_ctrl( op, rs, rs->sr_entry, + LDAP_SYNC_ADD, rs->sr_ctrls, 0, 1, &cookie ); + } else { + rs->sr_err = syncprov_state_ctrl( op, rs, rs->sr_entry, + LDAP_SYNC_ADD, rs->sr_ctrls, 0, 0, NULL ); + } } else if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS ) { struct berval cookie; @@ -2072,7 +2114,7 @@ syncprov_search_response( Operation *op, if ( op->o_abandon ) { ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); - syncprov_free_syncop( ss->ss_so ); + /* syncprov_ab_cleanup will free this syncop */ return SLAPD_ABANDON; } else { @@ -2246,6 +2288,9 @@ no_change: if ( !(op->o_sync_mode & SLA } goto shortcut; } + } else { + /* consumer doesn't have the right number of CSNs */ + changed = SS_CHANGED; } /* Do we have a sessionlog for this search? */ sl=si->si_logs; @@ -2388,8 +2433,15 @@ syncprov_operational( } if ( !ap ) { - if ( !rs->sr_flags & REP_ENTRY_MODIFIABLE ) { - rs->sr_entry = entry_dup( rs->sr_entry ); + if ( !(rs->sr_flags & REP_ENTRY_MODIFIABLE) ) { + Entry *e = entry_dup( rs->sr_entry ); + if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { + overlay_entry_release_ov( op, rs->sr_entry, 0, on ); + rs->sr_flags ^= REP_ENTRY_MUSTRELEASE; + } else if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) { + entry_free( rs->sr_entry ); + } + rs->sr_entry = e; rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED; a = attr_find( rs->sr_entry->e_attrs,