X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fsyncrepl.c;h=627e43a3d2e5458d9f46fea7121e4e10ce2937de;hb=e8d95fa072d7fc1b2f0ca485bb8278790870bda2;hp=eaccc3785ec59b742615750a99fb226e2f390c50;hpb=89e13bff5fc6cea6bf27e09e3244d4c3c3801f03;p=openldap diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index eaccc3785e..627e43a3d2 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2003-2008 The OpenLDAP Foundation. + * Copyright 2003-2009 The OpenLDAP Foundation. * Portions Copyright 2003 by IBM Corporation. * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation. * All rights reserved. @@ -41,6 +41,7 @@ typedef struct cookie_state { ldap_pvt_thread_mutex_t cs_mutex; int cs_num; int cs_age; + int cs_ref; struct berval *cs_vals; int *cs_sids; } cookie_state; @@ -343,7 +344,7 @@ ldap_sync_search( { BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; - LDAPControl c[2], *ctrls[3]; + LDAPControl c[3], *ctrls[4]; int rc; int rhint; char *base; @@ -417,14 +418,19 @@ ldap_sync_search( c[0].ldctl_iscritical = si->si_type < 0; ctrls[0] = &c[0]; + c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; + BER_BVZERO( &c[1].ldctl_value ); + c[1].ldctl_iscritical = 1; + ctrls[1] = &c[1]; + if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) { - c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; - c[1].ldctl_value = si->si_bindconf.sb_authzId; - c[1].ldctl_iscritical = 1; - ctrls[1] = &c[1]; - ctrls[2] = NULL; + c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; + c[2].ldctl_value = si->si_bindconf.sb_authzId; + c[2].ldctl_iscritical = 1; + ctrls[2] = &c[2]; + ctrls[3] = NULL; } else { - ctrls[1] = NULL; + ctrls[2] = NULL; } rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly, @@ -583,6 +589,8 @@ do_syncrep1( rc = LDAP_DEREF_NEVER; /* actually could allow DEREF_FINDING */ ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc ); + ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF ); + si->si_syncCookie.rid = si->si_rid; /* whenever there are multiple data sources possible, advertise sid */ @@ -724,7 +732,6 @@ do_syncrep2( syncinfo_t *si ) { LDAPControl **rctrls = NULL; - LDAPControl *rctrlp; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; @@ -781,6 +788,8 @@ do_syncrep2( while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE, tout_p, &msg ) ) > 0 ) { + LDAPControl *rctrlp = NULL; + if ( slapd_shutdown ) { rc = -2; goto done; @@ -789,18 +798,22 @@ do_syncrep2( case LDAP_RES_SEARCH_ENTRY: ldap_get_entry_controls( si->si_ld, msg, &rctrls ); /* we can't work without the control */ - rctrlp = NULL; if ( rctrls ) { LDAPControl **next; /* NOTE: make sure we use the right one; * a better approach would be to run thru * the whole list and take care of all */ + /* NOTE: since we issue the search request, + * we should know what controls to expect, + * and there should be none apart from the + * sync-related control */ rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next ); if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) ) { Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " "got search entry with multiple " "Sync State control\n", si->si_ridtxt, 0, 0 ); + ldap_controls_free( rctrls ); rc = -1; goto done; } @@ -851,6 +864,7 @@ do_syncrep2( } } } + op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; } } rc = 0; @@ -921,7 +935,26 @@ do_syncrep2( si->si_ridtxt, err, ldap_err2string( err ) ); } if ( rctrls ) { - rctrlp = *rctrls; + LDAPControl **next; + /* NOTE: make sure we use the right one; + * a better approach would be to run thru + * the whole list and take care of all */ + /* NOTE: since we issue the search request, + * we should know what controls to expect, + * and there should be none apart from the + * sync-related control */ + rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next ); + if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) ) + { + Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " + "got search result with multiple " + "Sync State control\n", si->si_ridtxt, 0, 0 ); + ldap_controls_free( rctrls ); + rc = -1; + goto done; + } + } + if ( rctrlp ) { ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER ); ber_scanf( ber, "{" /*"}"*/); @@ -938,6 +971,7 @@ do_syncrep2( if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { slap_parse_sync_cookie( &syncCookie, NULL ); + op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; } } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) @@ -1006,6 +1040,18 @@ do_syncrep2( "LDAP_RES_INTERMEDIATE", "NEW_COOKIE" ); ber_scanf( ber, "tm", &tag, &cookie ); + Debug( LDAP_DEBUG_SYNC, + "do_syncrep2: %s NEW_COOKIE: %s\n", + si->si_ridtxt, + cookie.bv_val, 0); + if ( !BER_BVISNULL( &cookie ) ) { + ch_free( syncCookie.octet_str.bv_val ); + ber_dupbv( &syncCookie.octet_str, &cookie ); + } + if (!BER_BVISNULL( &syncCookie.octet_str ) ) { + slap_parse_sync_cookie( &syncCookie, NULL ); + op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; + } break; case LDAP_TAG_SYNC_REFRESH_DELETE: case LDAP_TAG_SYNC_REFRESH_PRESENT: @@ -1035,6 +1081,7 @@ do_syncrep2( if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { slap_parse_sync_cookie( &syncCookie, NULL ); + op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; } } /* Defaults to TRUE */ @@ -1070,6 +1117,7 @@ do_syncrep2( if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { slap_parse_sync_cookie( &syncCookie, NULL ); + op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; compare_csns( &syncCookie_req, &syncCookie, &m ); } } @@ -1118,6 +1166,7 @@ do_syncrep2( if ( match < 0 ) { if ( si->si_refreshPresent == 1 && + si_tag != LDAP_TAG_SYNC_NEW_COOKIE && syncCookie_req.numcsns == syncCookie.numcsns ) { syncrepl_del_nonpresent( op, si, NULL, &syncCookie, m ); @@ -1207,16 +1256,27 @@ do_syncrepl( int rc = LDAP_SUCCESS; int dostop = 0; ber_socket_t s; - int i, defer = 1, fail = 0; + int i, defer = 1, fail = 0, freeinfo = 0; Backend *be; - Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 ); - if ( si == NULL ) return NULL; + if ( slapd_shutdown ) + return NULL; - /* There will never be more than one instance active */ - ldap_pvt_thread_mutex_lock( &si->si_mutex ); + Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 ); + + /* Don't get stuck here while a pause is initiated */ + while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) { + if ( slapd_shutdown ) + return NULL; + if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) + ldap_pvt_thread_yield(); + } + + if ( si->si_ctype < 1 ) { + goto deleted; + } switch( abs( si->si_type ) ) { case LDAP_SYNC_REFRESH_ONLY: @@ -1243,10 +1303,6 @@ do_syncrepl( connection_fake_init( &conn, &opbuf, ctx ); op = &opbuf.ob_op; - /* use global malloc for now */ - op->o_tmpmemctx = NULL; - op->o_tmpmfuncs = &ch_mfuncs; - op->o_managedsait = SLAP_CONTROL_NONCRITICAL; be = si->si_be; @@ -1305,8 +1361,13 @@ reload: goto reload; } +deleted: /* We got deleted while running on cn=config */ - if ( !si->si_ctype ) { + if ( si->si_ctype < 1 ) { + if ( si->si_ctype == -1 ) { + si->si_ctype = 0; + freeinfo = 1; + } if ( si->si_conn ) dostop = 1; rc = -1; @@ -1373,9 +1434,12 @@ reload: break; } - if ( !si->si_ctype + if ( si->si_ctype < 1 || !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) { - ldap_pvt_runqueue_remove( &slapd_rq, rtask ); + if ( si->si_re ) { + ldap_pvt_runqueue_remove( &slapd_rq, rtask ); + si->si_re = NULL; + } fail = RETRYNUM_TAIL; } else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) { if ( si->si_retrynum[i] > 0 ) @@ -1393,37 +1457,22 @@ reload: if ( rc ) { if ( fail == RETRYNUM_TAIL ) { Debug( LDAP_DEBUG_ANY, - "do_syncrepl: %s quitting\n", - si->si_ridtxt, 0, 0 ); + "do_syncrepl: %s rc %d quitting\n", + si->si_ridtxt, rc, 0 ); } else if ( fail > 0 ) { Debug( LDAP_DEBUG_ANY, - "do_syncrepl: %s retrying (%d retries left)\n", - si->si_ridtxt, fail, 0 ); + "do_syncrepl: %s rc %d retrying (%d retries left)\n", + si->si_ridtxt, rc, fail ); } else { Debug( LDAP_DEBUG_ANY, - "do_syncrepl: %s retrying\n", - si->si_ridtxt, 0, 0 ); + "do_syncrepl: %s rc %d retrying\n", + si->si_ridtxt, rc, 0 ); } } /* Do final delete cleanup */ - if ( !si->si_ctype ) { - cookie_state *cs = NULL; - syncinfo_t **sip; - - cs = be->be_syncinfo->si_cookieState; - for ( sip = &be->be_syncinfo; *sip != si; sip = &(*sip)->si_next ); - *sip = si->si_next; + if ( freeinfo ) { syncinfo_free( si, 0 ); - if ( !be->be_syncinfo ) { - SLAP_DBFLAGS( be ) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW); - if ( cs ) { - ch_free( cs->cs_sids ); - ber_bvarray_free( cs->cs_vals ); - ldap_pvt_thread_mutex_destroy( &cs->cs_mutex ); - ch_free( cs ); - } - } } return NULL; } @@ -1545,6 +1594,7 @@ syncrepl_message_to_op( prdn = BER_BVNULL, nrdn = BER_BVNULL, psup = BER_BVNULL, nsup = BER_BVNULL; int rc, deleteOldRdn = 0, freeReqDn = 0; + int do_graduate = 0; if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) { Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s " @@ -1577,7 +1627,16 @@ syncrepl_message_to_op( if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) { bdn = bvals[0]; - dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx ); + rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_message_to_op: %s " + "dn \"%s\" normalization failed (%d)", + si->si_ridtxt, bdn.bv_val, rc ); + rc = -1; + ch_free( bvals ); + goto done; + } ber_dupbv( &op->o_req_dn, &dn ); ber_dupbv( &op->o_req_ndn, &ndn ); slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); @@ -1613,6 +1672,7 @@ syncrepl_message_to_op( &slap_schema.si_ad_entryCSN->ad_cname ) ) { slap_queue_csn( op, bvals ); + do_graduate = 1; } ch_free( bvals ); } @@ -1657,6 +1717,7 @@ syncrepl_message_to_op( Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s be_add %s (%d)\n", si->si_ridtxt, op->o_req_dn.bv_val, rc ); + do_graduate = 0; } if ( e == op->ora_e ) be_entry_release_w( op, op->ora_e ); @@ -1669,6 +1730,7 @@ syncrepl_message_to_op( "syncrepl_message_to_op: %s be_modify %s (%d)\n", si->si_ridtxt, op->o_req_dn.bv_val, rc ); op->o_bd = si->si_be; + do_graduate = 0; } break; case LDAP_REQ_MODRDN: @@ -1712,16 +1774,19 @@ syncrepl_message_to_op( Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s be_modrdn %s (%d)\n", si->si_ridtxt, op->o_req_dn.bv_val, rc ); + do_graduate = 0; break; case LDAP_REQ_DELETE: rc = op->o_bd->be_delete( op, &rs ); Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s be_delete %s (%d)\n", si->si_ridtxt, op->o_req_dn.bv_val, rc ); + do_graduate = 0; break; } done: - slap_graduate_commit_csn( op ); + if ( do_graduate ) + slap_graduate_commit_csn( op ); op->o_bd = si->si_be; op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); BER_BVZERO( &op->o_csn ); @@ -1803,7 +1868,21 @@ syncrepl_message_to_entry( return -1; } - dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx ); + rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + /* One of the things that could happen is that the schema + * is not lined-up; this could result in unknown attributes. + * A value non conformant to the syntax should be unlikely, + * except when replicating between different versions + * of the software, or when syntax validation bugs are fixed + */ + Debug( LDAP_DEBUG_ANY, + "syncrepl_message_to_entry: " + "%s dn \"%s\" normalization failed (%d)", + si->si_ridtxt, bdn.bv_val, rc ); + return rc; + } + ber_dupbv( &op->o_req_dn, &dn ); ber_dupbv( &op->o_req_ndn, &ndn ); slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); @@ -2062,6 +2141,7 @@ syncrepl_entry( op->o_time = slap_get_time(); op->ors_tlimit = SLAP_NO_LIMIT; op->ors_slimit = 1; + op->ors_limit = NULL; op->ors_attrs = slap_anlist_all_attributes; op->ors_attrsonly = 0; @@ -2073,12 +2153,10 @@ syncrepl_entry( dni.new_entry = entry; dni.modlist = modlist; - if ( limits_check( op, &rs_search ) == 0 ) { - rc = be->be_search( op, &rs_search ); - Debug( LDAP_DEBUG_SYNC, - "syncrepl_entry: %s be_search (%d)\n", - si->si_ridtxt, rc, 0 ); - } + rc = be->be_search( op, &rs_search ); + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s be_search (%d)\n", + si->si_ridtxt, rc, 0 ); if ( !BER_BVISNULL( &op->ors_filterstr ) ) { slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx ); @@ -2132,8 +2210,8 @@ retry_add:; rc = op->o_bd->be_add( op, &rs_add ); Debug( LDAP_DEBUG_SYNC, - "syncrepl_entry: %s be_add (%d)\n", - si->si_ridtxt, rc, 0 ); + "syncrepl_entry: %s be_add %s (%d)\n", + si->si_ridtxt, op->o_req_dn.bv_val, rc ); switch ( rs_add.sr_err ) { case LDAP_SUCCESS: if ( op->ora_e == entry ) { @@ -2195,10 +2273,11 @@ retry_add:; default: Debug( LDAP_DEBUG_ANY, - "syncrepl_entry: %s be_add failed (%d)\n", - si->si_ridtxt, rs_add.sr_err, 0 ); + "syncrepl_entry: %s be_add %s failed (%d)\n", + si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err ); break; } + syncCSN = NULL; op->o_bd = be; goto done; } @@ -2208,7 +2287,7 @@ retry_add:; if ( dni.renamed ) { struct berval noldp, newp; Modifications *mod, **modtail, **ml, *m2; - int i, got_replace = 0; + int i, got_replace = 0, just_rename = 0; op->o_tag = LDAP_REQ_MODRDN; dnRdn( &entry->e_name, &op->orr_newrdn ); @@ -2289,6 +2368,12 @@ retry_add:; break; } } + if ( !mod->sml_numvals ) { + /* Drop this op */ + *ml = mod->sml_next; + mod->sml_next = NULL; + slap_mods_free( mod, 1 ); + } break; } } @@ -2328,7 +2413,7 @@ retry_add:; } } } - + /* RDNs must be NUL-terminated for back-ldap */ noldp = op->orr_newrdn; ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx ); @@ -2368,8 +2453,12 @@ retry_add:; */ if ( dni.mods ) { mod = dni.mods; + /* don't set a CSN for the rename op */ + if ( syncCSN ) + slap_graduate_commit_csn( op ); } else { mod = op->orr_modlist; + just_rename = 1; } for ( ; mod->sml_next; mod=mod->sml_next ); mod->sml_next = m2; @@ -2381,12 +2470,17 @@ retry_add:; slap_mods_free( op->orr_modlist, 1 ); Debug( LDAP_DEBUG_SYNC, - "syncrepl_entry: %s be_modrdn (%d)\n", - si->si_ridtxt, rc, 0 ); + "syncrepl_entry: %s be_modrdn %s (%d)\n", + si->si_ridtxt, op->o_req_dn.bv_val, rc ); op->o_bd = be; /* Renamed entries may still have other mods so just fallthru */ op->o_req_dn = entry->e_name; op->o_req_ndn = entry->e_nname; + /* Use CSN on the modify */ + if ( just_rename ) + syncCSN = NULL; + else if ( syncCSN ) + slap_queue_csn( op, syncCSN ); } if ( dni.mods ) { op->o_tag = LDAP_REQ_MODIFY; @@ -2398,18 +2492,23 @@ retry_add:; slap_mods_free( op->orm_modlist, 1 ); op->orm_no_opattrs = 0; Debug( LDAP_DEBUG_SYNC, - "syncrepl_entry: %s be_modify (%d)\n", - si->si_ridtxt, rc, 0 ); + "syncrepl_entry: %s be_modify %s (%d)\n", + si->si_ridtxt, op->o_req_dn.bv_val, rc ); if ( rs_modify.sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "syncrepl_entry: %s be_modify failed (%d)\n", si->si_ridtxt, rs_modify.sr_err, 0 ); } + syncCSN = NULL; op->o_bd = be; } else if ( !dni.renamed ) { Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s entry unchanged, ignored (%s)\n", si->si_ridtxt, op->o_req_dn.bv_val, 0 ); + if ( syncCSN ) { + slap_graduate_commit_csn( op ); + syncCSN = NULL; + } } goto done; case LDAP_SYNC_DELETE : @@ -2420,8 +2519,8 @@ retry_add:; op->o_bd = si->si_wbe; rc = op->o_bd->be_delete( op, &rs_delete ); Debug( LDAP_DEBUG_SYNC, - "syncrepl_entry: %s be_delete (%d)\n", - si->si_ridtxt, rc, 0 ); + "syncrepl_entry: %s be_delete %s (%d)\n", + si->si_ridtxt, op->o_req_dn.bv_val, rc ); while ( rs_delete.sr_err == LDAP_SUCCESS && op->o_delete_glue_parent ) { @@ -2438,6 +2537,7 @@ retry_add:; break; } } + syncCSN = NULL; op->o_bd = be; } goto done; @@ -2540,40 +2640,43 @@ syncrepl_del_nonpresent( si->si_refreshDelete ^= NP_DELETE_ONE; } else { Filter *cf, *of; + Filter mmf[2]; + AttributeAssertion mmaa; 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; op->ors_attrs = an; op->ors_slimit = SLAP_NO_LIMIT; + 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 ); /* In multimaster, updates can continue to arrive while * we're searching. Limit the search result to entries - * older than all of our cookie CSNs. + * older than our newest cookie CSN. */ 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 = mmf; f->f_choice = LDAP_FILTER_AND; - f->f_next = NULL; + f->f_next = op->ors_filter; f->f_and = f+1; of = f->f_and; + f = of; + f->f_choice = LDAP_FILTER_LE; + f->f_ava = &mmaa; + f->f_av_desc = slap_schema.si_ad_entryCSN; + f->f_next = NULL; + BER_BVZERO( &f->f_av_value ); for ( i=0; inumcsns; 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; + if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 ) + f->f_av_value = sc->ctxcsn[i]; } - f->f_next = op->ors_filter; of = op->ors_filter; - op->ors_filter = cf; + op->ors_filter = mmf; filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); } else { cf = NULL; @@ -2581,11 +2684,9 @@ syncrepl_del_nonpresent( } op->o_nocaching = 1; - if ( limits_check( op, &rs_search ) == 0 ) { - rc = be->be_search( op, &rs_search ); - } + + rc = be->be_search( op, &rs_search ); 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 ); @@ -2848,6 +2949,9 @@ syncrepl_updateCookie( Backend *be = op->o_bd; Modifications mod; struct berval first = BER_BVNULL; +#ifdef CHECK_CSN + Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; +#endif int rc, i, j; ber_len_t len; @@ -2864,6 +2968,15 @@ syncrepl_updateCookie( ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); +#ifdef CHECK_CSN + for ( i=0; inumcsns; i++ ) { + assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i )); + } + for ( i=0; isi_cookieState->cs_num; i++ ) { + assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i )); + } +#endif + /* 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 ); @@ -2966,6 +3079,12 @@ syncrepl_updateCookie( if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 ); op->o_tmpfree( mod.sml_values, op->o_tmpmemctx ); +#ifdef CHECK_CSN + for ( i=0; isi_cookieState->cs_num; i++ ) { + assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i )); + } +#endif + return rc; } @@ -3138,33 +3257,37 @@ dn_callback( struct berval old_p, new_p; int is_ctx, new_sup = 0; - /* Make sure new entry is actually newer than old entry */ - old = attr_find( rs->sr_entry->e_attrs, - slap_schema.si_ad_entryCSN ); - new = attr_find( dni->new_entry->e_attrs, - slap_schema.si_ad_entryCSN ); - if ( new && old ) { - 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, - new->a_vals[0].bv_val, len ); - if ( rc > 0 ) { - Debug( LDAP_DEBUG_SYNC, - "dn_callback : new entry is older than ours " - "%s ours %s, new %s\n", - rs->sr_entry->e_name.bv_val, - old->a_vals[0].bv_val, - new->a_vals[0].bv_val ); - return LDAP_SUCCESS; - } else if ( rc == 0 ) { - Debug( LDAP_DEBUG_SYNC, - "dn_callback : entries have identical CSN " - "%s %s\n", - rs->sr_entry->e_name.bv_val, - old->a_vals[0].bv_val, 0 ); - return LDAP_SUCCESS; + /* If old entry is not a glue entry, make sure new entry + * is actually newer than old entry + */ + if ( !is_entry_glue( rs->sr_entry )) { + old = attr_find( rs->sr_entry->e_attrs, + slap_schema.si_ad_entryCSN ); + new = attr_find( dni->new_entry->e_attrs, + slap_schema.si_ad_entryCSN ); + if ( new && old ) { + 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, + new->a_vals[0].bv_val, len ); + if ( rc > 0 ) { + Debug( LDAP_DEBUG_SYNC, + "dn_callback : new entry is older than ours " + "%s ours %s, new %s\n", + rs->sr_entry->e_name.bv_val, + old->a_vals[0].bv_val, + new->a_vals[0].bv_val ); + return LDAP_SUCCESS; + } else if ( rc == 0 ) { + Debug( LDAP_DEBUG_SYNC, + "dn_callback : entries have identical CSN " + "%s %s\n", + rs->sr_entry->e_name.bv_val, + old->a_vals[0].bv_val, 0 ); + return LDAP_SUCCESS; + } } } @@ -3290,8 +3413,8 @@ dn_callback( * stays co-located with the other mod opattrs. But only * if we know there are other valid mods. */ - if ( old->a_desc == slap_schema.si_ad_modifiersName && - dni->mods ) + if ( dni->mods && ( old->a_desc == slap_schema.si_ad_modifiersName || + old->a_desc == slap_schema.si_ad_modifyTimestamp )) attr_cmp( op, NULL, new, &modtail, &ml ); else attr_cmp( op, old, new, &modtail, &ml ); @@ -3502,12 +3625,9 @@ syncinfo_free( syncinfo_t *sie, int free_all ) { syncinfo_t *si_next; - if ( free_all && sie->si_cookieState ) { - 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 ); - } + Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n", + sie->si_ridtxt, 0, 0 ); + do { si_next = sie->si_next; @@ -3519,20 +3639,21 @@ syncinfo_free( syncinfo_t *sie, int free_all ) ldap_unbind_ext( sie->si_ld, NULL, NULL ); } - /* 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 ) ) - ldap_pvt_runqueue_stoptask( &slapd_rq, sie->si_re ); - ldap_pvt_runqueue_remove( &slapd_rq, sie->si_re ); + struct re_s *re = sie->si_re; + sie->si_re = 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 ); + ldap_pvt_runqueue_remove( &slapd_rq, re ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); } - - ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); - ldap_pvt_thread_mutex_destroy( &sie->si_mutex ); - + + ldap_pvt_thread_mutex_destroy( &sie->si_mutex ); + bindconf_free( &sie->si_bindconf ); - + if ( sie->si_filterstr.bv_val ) { ch_free( sie->si_filterstr.bv_val ); } @@ -3608,6 +3729,13 @@ syncinfo_free( syncinfo_t *sie, int free_all ) } ch_free( npe ); } + sie->si_cookieState->cs_ref--; + if ( !sie->si_cookieState->cs_ref ) { + 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 ); + } ch_free( sie ); sie = si_next; } while ( free_all && si_next ); @@ -4204,6 +4332,8 @@ add_syncrepl( rc = parse_syncrepl_line( c, si ); if ( rc == 0 ) { + LDAPURLDesc *lud; + /* Must be LDAPv3 because we need controls */ switch ( si->si_bindconf.sb_version ) { case 0: @@ -4221,24 +4351,35 @@ add_syncrepl( return 1; } + if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "<%s> invalid URL", c->argv[0] ); + Debug( LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val ); + return 1; + } + si->si_be = c->be; if ( slapMode & SLAP_SERVER_MODE ) { - Listener **l = slapd_get_listeners(); int isMe = 0; - - /* check if URL points to current server. If so, ignore - * this configuration. We require an exact match. Just - * in case they really want to do this, they can vary - * the case of the URL to allow it. + /* check if consumer points to current server and database. + * If so, ignore this configuration. */ - if ( l && !SLAP_DBHIDDEN( c->be ) ) { + if ( !SLAP_DBHIDDEN( c->be ) ) { int i; - for ( i=0; l[i]; i++ ) { - if ( bvmatch( &l[i]->sl_url, &si->si_bindconf.sb_uri ) ) { + /* if searchbase doesn't match current DB suffix, + * assume it's different + */ + for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) { + if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) { isMe = 1; break; } } + /* if searchbase matches, see if URLs match */ + if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val, + lud ) == NULL ) + isMe = 0; } if ( !isMe ) { @@ -4257,6 +4398,7 @@ add_syncrepl( /* mirrormode still needs to see this flag in tool mode */ rc = config_sync_shadow( c ) ? -1 : 0; } + ldap_free_urldesc( lud ); } #ifdef HAVE_TLS @@ -4273,13 +4415,23 @@ add_syncrepl( BER_BVISNULL( &si->si_bindconf.sb_uri ) ? "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 ); if ( c->be->be_syncinfo ) { + syncinfo_t *sip; + si->si_cookieState = c->be->be_syncinfo->si_cookieState; + + /* add new syncrepl to end of list (same order as when deleting) */ + for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next ); + sip->si_next = si; } else { si->si_cookieState = ch_calloc( 1, sizeof( cookie_state )); ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex ); + + c->be->be_syncinfo = si; } - si->si_next = c->be->be_syncinfo; - c->be->be_syncinfo = si; + si->si_cookieState->cs_ref++; + + si->si_next = NULL; + return 0; } } @@ -4475,28 +4627,38 @@ syncrepl_config( ConfigArgs *c ) } return 1; } else if ( c->op == LDAP_MOD_DELETE ) { - cookie_state *cs = NULL; + int isrunning = 0; if ( c->be->be_syncinfo ) { syncinfo_t *si, **sip; int i; - cs = c->be->be_syncinfo->si_cookieState; 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_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 ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) { + isrunning = 1; + } else { + 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 ); + } + ldap_pvt_thread_mutex_unlock( &si->si_mutex ); + } } - if ( si->si_re && isrunning ) { - si->si_ctype = 0; + if ( isrunning ) { + si->si_ctype = -1; + si->si_next = NULL; } else { syncinfo_free( si, 0 ); } @@ -4508,12 +4670,7 @@ syncrepl_config( ConfigArgs *c ) } } if ( !c->be->be_syncinfo ) { - SLAP_DBFLAGS( c->be ) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW); - if ( cs ) { - ber_bvarray_free( cs->cs_vals ); - ldap_pvt_thread_mutex_destroy( &cs->cs_mutex ); - ch_free( cs ); - } + SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK; } return 0; }