--- servers/slapd/overlays/syncprov.c 2008/03/20 23:09:24 1.224 +++ servers/slapd/overlays/syncprov.c 2009/02/11 21:00:00 1.257 @@ -1,8 +1,8 @@ -/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.223 2008/03/19 23:31:42 hyc Exp $ */ +/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.256 2009/01/28 01:03:07 hyc Exp $ */ /* syncprov.c - syncrepl provider */ /* This work is part of OpenLDAP Software . * - * Copyright 2004-2008 The OpenLDAP Foundation. + * Copyright 2004-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -393,9 +393,6 @@ static struct berval generic_filterstr = static int syncprov_findbase( Operation *op, fbase_cookie *fc ) { - opcookie *opc = op->o_callback->sc_private; - slap_overinst *on = opc->son; - /* Use basic parameters from syncrepl search, but use * current op's threadctx / tmpmemctx */ @@ -404,7 +401,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 +408,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 +429,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 +494,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 +585,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,17 +611,23 @@ 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 ) ) { + if ( fop.ors_filterstr.bv_len >= sizeof( buf ) ) { return LDAP_OTHER; } fop.ors_attrsonly = 0; @@ -663,7 +664,7 @@ again: 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 ) ) { + if ( fop.ors_filterstr.bv_len >= sizeof( buf ) ) { return LDAP_OTHER; } fop.ors_attrsonly = 1; @@ -696,10 +697,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 +738,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 ); @@ -795,7 +800,7 @@ syncprov_sendresp( Operation *op, opcook rs.sr_entry = *e; if ( rs.sr_entry->e_private ) rs.sr_flags = REP_ENTRY_MUSTRELEASE; - if ( opc->sreference ) { + if ( opc->sreference && so->s_op->o_managedsait <= SLAP_CONTROL_IGNORED ) { rs.sr_ref = get_entry_referrals( op, rs.sr_entry ); rs.sr_err = send_search_reference( op, &rs ); ber_bvarray_free( rs.sr_ref ); @@ -818,7 +823,7 @@ syncprov_sendresp( Operation *op, opcook e_uuid.e_name = opc->sdn; e_uuid.e_nname = opc->sndn; rs.sr_entry = &e_uuid; - if ( opc->sreference ) { + if ( opc->sreference && so->s_op->o_managedsait <= SLAP_CONTROL_IGNORED ) { struct berval bv = BER_BVNULL; rs.sr_ref = &bv; rs.sr_err = send_search_reference( op, &rs ); @@ -903,6 +908,10 @@ syncprov_qplay( Operation *op, struct re } else { /* bail out on any error */ ldap_pvt_runqueue_remove( &slapd_rq, rtask ); + + /* Prevent duplicate remove */ + if ( so->s_qtask == rtask ) + so->s_qtask = NULL; } ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); ldap_pvt_thread_mutex_unlock( &so->s_mutex ); @@ -1172,10 +1181,15 @@ syncprov_matchops( Operation *op, opcook for (ss = si->si_ops, sprev = (syncops *)&si->si_ops; ss; sprev = ss, ss=snext) { + Operation op2; + Opheader oh; 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 +1230,17 @@ syncprov_matchops( Operation *op, opcook } } + if ( fc.fscope ) { + op2 = *ss->s_op; + oh = *op->o_hdr; + oh.oh_conn = ss->s_op->o_conn; + oh.oh_connid = ss->s_op->o_connid; + op2.o_hdr = &oh; + 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 ); @@ -1236,6 +1259,12 @@ syncprov_matchops( Operation *op, opcook /* send DELETE */ syncprov_qresp( opc, ss, LDAP_SYNC_DELETE ); } + if ( !saveit && found ) { + /* Decrement s_inuse, was incremented when called + * with saveit == TRUE + */ + syncprov_free_syncop( ss ); + } } ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); @@ -1310,13 +1339,20 @@ syncprov_checkpoint( Operation *op, Slap SlapReply rsm = { 0 }; slap_callback cb = {0}; BackendDB be; +#ifdef CHECK_CSN + Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; + int i; + for ( i=0; isi_numcsns; i++ ) { + assert( !syn->ssyn_validate( syn, si->si_ctxcsn+i )); + } +#endif mod.sml_numvals = si->si_numcsns; mod.sml_values = si->si_ctxcsn; mod.sml_nvalues = NULL; mod.sml_desc = slap_schema.si_ad_contextCSN; mod.sml_op = LDAP_MOD_REPLACE; - mod.sml_flags = 0; + mod.sml_flags = SLAP_MOD_INTERNAL; mod.sml_next = NULL; cb.sc_response = slap_null_cb; @@ -1338,6 +1374,11 @@ syncprov_checkpoint( Operation *op, Slap if ( mod.sml_next != NULL ) { slap_mods_free( mod.sml_next, 1 ); } +#ifdef CHECK_CSN + for ( i=0; isi_numcsns; i++ ) { + assert( !syn->ssyn_validate( syn, si->si_ctxcsn+i )); + } +#endif } static void @@ -1531,10 +1572,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 ); - } - Debug( LDAP_DEBUG_SYNC, "syncprov_playlog: cookie=%s\n", cookie.bv_val, 0, 0 ); + 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, delcsn[0].bv_len ? &cookie : NULL, 0, uuids, 1 ); - op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); + if ( delcsn[0].bv_len ) { + op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); + } } op->o_tmpfree( uuids, op->o_tmpmemctx ); } @@ -1582,12 +1622,23 @@ syncprov_op_response( Operation *op, Sla { struct berval maxcsn = BER_BVNULL; char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; - int do_check = 0, have_psearches; + int do_check = 0, have_psearches, foundit; /* Update our context CSN */ cbuf[0] = '\0'; ldap_pvt_thread_rdwr_wlock( &si->si_csn_rwlock ); - slap_get_commit_csn( op, &maxcsn ); + slap_get_commit_csn( op, &maxcsn, &foundit ); + 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, &foundit ); + op->o_bd = be; + } if ( !BER_BVISNULL( &maxcsn ) ) { int i, sid; strcpy( cbuf, maxcsn.bv_val ); @@ -1608,11 +1659,14 @@ syncprov_op_response( Operation *op, Sla sizeof(int)); si->si_sids[i] = sid; } + } else if ( !foundit ) { + /* 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 */ - if ( SLAP_SYNC_SHADOW( op->o_bd ) && - op->o_msgid == SLAP_SYNC_UPDATE_MSGID ) { + if ( op->o_dont_replicate ) { ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); return SLAP_CB_CONTINUE; } @@ -1641,8 +1695,11 @@ syncprov_op_response( Operation *op, Sla ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); } - opc->sctxcsn.bv_len = maxcsn.bv_len; - opc->sctxcsn.bv_val = cbuf; + /* only update consumer ctx if this is the greatest csn */ + if ( bvmatch( &maxcsn, &op->o_csn )) { + opc->sctxcsn.bv_len = maxcsn.bv_len; + opc->sctxcsn.bv_val = cbuf; + } /* Handle any persistent searches */ ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); @@ -1904,6 +1961,7 @@ syncprov_detach_op( Operation *op, synco op2->o_time = op->o_time; op2->o_bd = on->on_info->oi_origdb; op2->o_request = op->o_request; + op2->o_managedsait = op->o_managedsait; LDAP_SLIST_FIRST(&op2->o_extra)->oe_key = on; LDAP_SLIST_NEXT(LDAP_SLIST_FIRST(&op2->o_extra), oe_next) = NULL; @@ -1970,6 +2028,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 ) { @@ -2035,8 +2094,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; @@ -2068,17 +2135,16 @@ syncprov_search_response( Operation *op, op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); /* Detach this Op from frontend control */ - ldap_pvt_thread_mutex_lock( &ss->ss_so->s_mutex ); ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); /* But not if this connection was closed along the way */ 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 { + ldap_pvt_thread_mutex_lock( &ss->ss_so->s_mutex ); /* Turn off the refreshing flag */ ss->ss_so->s_flags ^= PS_IS_REFRESHING; @@ -2089,8 +2155,8 @@ syncprov_search_response( Operation *op, /* If there are queued responses, fire them off */ if ( ss->ss_so->s_res ) syncprov_qstart( ss->ss_so ); + ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); } - ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); return LDAP_SUCCESS; } @@ -2121,7 +2187,6 @@ syncprov_op_search( Operation *op, SlapR } srs = op->o_controls[slap_cids.sc_LDAPsync]; - op->o_managedsait = SLAP_CONTROL_NONCRITICAL; /* If this is a persistent search, set it up right away */ if ( op->o_sync_mode & SLAP_SYNC_PERSIST ) { @@ -2249,6 +2314,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; @@ -2277,6 +2345,15 @@ no_change: if ( !(op->o_sync_mode & SLA send_ldap_error( op, rs, LDAP_SYNC_REFRESH_REQUIRED, "sync cookie is stale" ); return rs->sr_err; } + if ( srs->sr_state.ctxcsn ) { + ber_bvarray_free_x( srs->sr_state.ctxcsn, op->o_tmpmemctx ); + srs->sr_state.ctxcsn = NULL; + } + if ( srs->sr_state.sids ) { + slap_sl_free( srs->sr_state.sids, op->o_tmpmemctx ); + srs->sr_state.sids = NULL; + } + srs->sr_state.numcsns = 0; } else { gotstate = 1; /* If changed and doing Present lookup, send Present UUIDs */ @@ -2391,8 +2468,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, @@ -2448,7 +2532,11 @@ static ConfigOCs spocs[] = { "NAME 'olcSyncProvConfig' " "DESC 'SyncRepl Provider configuration' " "SUP olcOverlayConfig " - "MAY ( olcSpCheckpoint $ olcSpSessionlog $ olcSpNoPresent ) )", + "MAY ( olcSpCheckpoint " + "$ olcSpSessionlog " + "$ olcSpNoPresent " + "$ olcSpReloadHint " + ") )", Cft_Overlay, spcfg }, { NULL, 0, NULL } }; @@ -2467,7 +2555,7 @@ sp_cf_gen(ConfigArgs *c) struct berval bv; bv.bv_len = snprintf( c->cr_msg, sizeof( c->cr_msg ), "%d %d", si->si_chkops, si->si_chktime ); - if ( bv.bv_len < 0 || bv.bv_len >= sizeof( c->cr_msg ) ) { + if ( bv.bv_len >= sizeof( c->cr_msg ) ) { rc = 1; } else { bv.bv_val = c->cr_msg; @@ -2661,7 +2749,7 @@ syncprov_db_open( si->si_sids = slap_parse_csn_sids( si->si_ctxcsn, a->a_numvals, NULL ); } overlay_entry_release_ov( op, e, 0, on ); - if ( si->si_ctxcsn ) { + if ( si->si_ctxcsn && !SLAP_DBCLEAN( be )) { op->o_req_dn = be->be_suffix[0]; op->o_req_ndn = be->be_nsuffix[0]; op->ors_scope = LDAP_SCOPE_SUBTREE;