From 15828a87e281191a7d9ec6acaaf89ece8da96c9b Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Wed, 26 Aug 2009 01:43:35 +0000 Subject: [PATCH] Fix backwards commit. Oops. --- servers/slapd/syncrepl.c | 465 ++++++++++++++++++++++++--------------- 1 file changed, 284 insertions(+), 181 deletions(-) diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index f10c36b600..22496b66b3 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -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; @@ -863,6 +864,7 @@ do_syncrep2( } } } + op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; } } rc = 0; @@ -969,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 ) @@ -1047,6 +1050,7 @@ do_syncrep2( } 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: @@ -1077,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 */ @@ -1112,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 ); } } @@ -1250,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; + + Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 ); - /* There will never be more than one instance active */ - ldap_pvt_thread_mutex_lock( &si->si_mutex ); + /* 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: @@ -1286,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; @@ -1348,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; @@ -1416,7 +1434,7 @@ reload: break; } - if ( !si->si_ctype + if ( si->si_ctype < 1 || !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) { if ( si->si_re ) { ldap_pvt_runqueue_remove( &slapd_rq, rtask ); @@ -1439,24 +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 = si->si_cookieState; - syncinfo_free( si, ( !be->be_syncinfo || - be->be_syncinfo->si_cookieState != cs )); + if ( freeinfo ) { + syncinfo_free( si, 0 ); } return NULL; } @@ -1578,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 " @@ -1603,6 +1620,13 @@ syncrepl_message_to_op( op->o_tag = LBER_DEFAULT; op->o_bd = si->si_wbe; + if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_message_to_op: %s got empty dn", + si->si_ridtxt, 0, 0 ); + return LDAP_OTHER; + } + while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) ) == LDAP_SUCCESS ) { if ( bv.bv_val == NULL ) @@ -1610,7 +1634,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 ); @@ -1646,6 +1679,7 @@ syncrepl_message_to_op( &slap_schema.si_ad_entryCSN->ad_cname ) ) { slap_queue_csn( op, bvals ); + do_graduate = 1; } ch_free( bvals ); } @@ -1690,6 +1724,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 ); @@ -1702,6 +1737,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: @@ -1745,16 +1781,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 ); @@ -1825,6 +1864,13 @@ syncrepl_message_to_entry( return rc; } + if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_message_to_entry: %s got empty dn", + si->si_ridtxt, 0, 0 ); + return LDAP_OTHER; + } + if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) { /* NOTE: this could be done even before decoding the DN, * although encoding errors wouldn't be detected */ @@ -1836,7 +1882,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 ); @@ -2164,8 +2224,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 ) { @@ -2227,10 +2287,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; } @@ -2321,6 +2382,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; } } @@ -2360,7 +2427,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 ); @@ -2417,14 +2484,16 @@ 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 ( syncCSN && !just_rename ) + if ( just_rename ) + syncCSN = NULL; + else if ( syncCSN ) slap_queue_csn( op, syncCSN ); } if ( dni.mods ) { @@ -2437,18 +2506,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 : @@ -2459,8 +2533,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 ) { @@ -2477,6 +2551,7 @@ retry_add:; break; } } + syncCSN = NULL; op->o_bd = be; } goto done; @@ -2887,11 +2962,12 @@ 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, csn_changed = 0; + int rc, i, j; ber_len_t len; slap_callback cb = { NULL }; @@ -2933,7 +3009,13 @@ 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]; - csn_changed = 1; + if ( BER_BVISNULL( &first ) ) { + first = syncCookie->ctxcsn[i]; + + } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) + { + first = syncCookie->ctxcsn[i]; + } } break; } @@ -2943,16 +3025,23 @@ syncrepl_updateCookie( ( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx ); mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i]; BER_BVZERO( &mod.sml_values[mod.sml_numvals] ); - csn_changed = 1; + if ( BER_BVISNULL( &first ) ) { + first = syncCookie->ctxcsn[i]; + } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) + { + first = syncCookie->ctxcsn[i]; + } } } /* Should never happen, ITS#5065 */ - if ( !csn_changed ) { + if ( BER_BVISNULL( &first )) { ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); op->o_tmpfree( mod.sml_values, op->o_tmpmemctx ); return 0; } op->o_bd = si->si_wbe; + slap_queue_csn( op, &first ); + op->o_tag = LDAP_REQ_MODIFY; cb.sc_response = null_callback; @@ -3013,6 +3102,10 @@ syncrepl_updateCookie( return rc; } +/* Compare the attribute from the old entry to the one in the new + * entry. The Modifications from the new entry will either be left + * in place, or changed to an Add or Delete as needed. + */ static void attr_cmp( Operation *op, Attribute *old, Attribute *new, Modifications ***mret, Modifications ***mcur ) @@ -3156,6 +3249,86 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new, *mret = modtail; } +/* Generate a set of modifications to change the old entry into the + * new one. On input ml is a list of modifications equivalent to + * the new entry. It will be massaged and the result will be stored + * in mods. + */ +void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new, + Modifications **mods, Modifications **ml, int is_ctx) +{ + Modifications **modtail = mods; + + /* We assume that attributes are saved in the same order + * in the remote and local databases. So if we walk through + * the attributeDescriptions one by one they should match in + * lock step. If not, look for an add or delete. + */ + while ( old && new ) + { + /* If we've seen this before, use its mod now */ + if ( new->a_flags & SLAP_ATTR_IXADD ) { + attr_cmp( op, NULL, new, &modtail, &ml ); + new = new->a_next; + continue; + } + /* Skip contextCSN */ + if ( is_ctx && old->a_desc == + slap_schema.si_ad_contextCSN ) { + old = old->a_next; + continue; + } + + if ( old->a_desc != new->a_desc ) { + Modifications *mod; + Attribute *tmp; + + /* If it's just been re-added later, + * remember that we've seen it. + */ + tmp = attr_find( new, old->a_desc ); + if ( tmp ) { + tmp->a_flags |= SLAP_ATTR_IXADD; + } else { + /* If it's a new attribute, pull it in. + */ + tmp = attr_find( old, new->a_desc ); + if ( !tmp ) { + attr_cmp( op, NULL, new, &modtail, &ml ); + new = new->a_next; + continue; + } + /* Delete old attr */ + mod = ch_malloc( sizeof( Modifications ) ); + mod->sml_op = LDAP_MOD_DELETE; + mod->sml_flags = 0; + mod->sml_desc = old->a_desc; + mod->sml_type = mod->sml_desc->ad_cname; + mod->sml_numvals = 0; + mod->sml_values = NULL; + mod->sml_nvalues = NULL; + *modtail = mod; + modtail = &mod->sml_next; + } + old = old->a_next; + continue; + } + /* kludge - always update modifiersName so that it + * stays co-located with the other mod opattrs. But only + * if we know there are other valid mods. + */ + if ( *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 ); + new = new->a_next; + old = old->a_next; + } + *modtail = *ml; + *ml = NULL; +} + static int dn_callback( Operation* op, @@ -3186,8 +3359,6 @@ dn_callback( * 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_objectClass ); old = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ); new = attr_find( dni->new_entry->e_attrs, @@ -3278,78 +3449,9 @@ dn_callback( */ } - modtail = &dni->mods; - ml = dni->modlist; - - /* We assume that attributes are saved in the same order - * in the remote and local databases. So if we walk through - * the attributeDescriptions one by one they should match in - * lock step. If not, look for an add or delete. - */ - for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs; - old && new; ) - { - /* If we've seen this before, use its mod now */ - if ( new->a_flags & SLAP_ATTR_IXADD ) { - attr_cmp( op, NULL, new, &modtail, &ml ); - new = new->a_next; - continue; - } - /* Skip contextCSN */ - if ( is_ctx && old->a_desc == - slap_schema.si_ad_contextCSN ) { - old = old->a_next; - continue; - } - - if ( old->a_desc != new->a_desc ) { - Modifications *mod; - Attribute *tmp; - - /* If it's just been re-added later, - * remember that we've seen it. - */ - tmp = attr_find( new, old->a_desc ); - if ( tmp ) { - tmp->a_flags |= SLAP_ATTR_IXADD; - } else { - /* If it's a new attribute, pull it in. - */ - tmp = attr_find( old, new->a_desc ); - if ( !tmp ) { - attr_cmp( op, NULL, new, &modtail, &ml ); - new = new->a_next; - continue; - } - /* Delete old attr */ - mod = ch_malloc( sizeof( Modifications ) ); - mod->sml_op = LDAP_MOD_DELETE; - mod->sml_flags = 0; - mod->sml_desc = old->a_desc; - mod->sml_type = mod->sml_desc->ad_cname; - mod->sml_numvals = 0; - mod->sml_values = NULL; - mod->sml_nvalues = NULL; - *modtail = mod; - modtail = &mod->sml_next; - } - old = old->a_next; - continue; - } - /* kludge - always update modifiersName so that it - * stays co-located with the other mod opattrs. But only - * if we know there are other valid 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 ); - new = new->a_next; - old = old->a_next; - } - *modtail = *ml; - *ml = NULL; + syncrepl_diff_entry( op, rs->sr_entry->e_attrs, + dni->new_entry->e_attrs, &dni->mods, dni->modlist, + is_ctx ); } } } else if ( rs->sr_type == REP_RESULT ) { @@ -3552,12 +3654,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; @@ -3569,20 +3668,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 ); } @@ -3658,6 +3758,15 @@ syncinfo_free( syncinfo_t *sie, int free_all ) } ch_free( npe ); } + if ( sie->si_cookieState ) { + 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 ); @@ -3713,21 +3822,6 @@ enum { GOT_REQUIRED = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE) }; -static struct { - struct berval key; - int val; -} scopes[] = { - { BER_BVC("base"), LDAP_SCOPE_BASE }, - { BER_BVC("one"), LDAP_SCOPE_ONELEVEL }, - { BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL }, /* OpenLDAP extension */ - { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE }, - { BER_BVC("subord"), LDAP_SCOPE_SUBORDINATE }, - { BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE }, - { BER_BVC("sub"), LDAP_SCOPE_SUBTREE }, - { BER_BVC("subtree"), LDAP_SCOPE_SUBTREE }, /* OpenLDAP extension */ - { BER_BVNULL, 0 } -}; - static slap_verbmasks datamodes[] = { { BER_BVC("default"), SYNCDATA_DEFAULT }, { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG }, @@ -3945,19 +4039,15 @@ parse_syncrepl_line( { int j; val = c->argv[ i ] + STRLENOF( SCOPESTR "=" ); - for ( j = 0; !BER_BVISNULL(&scopes[j].key); j++ ) { - if (!strcasecmp( val, scopes[j].key.bv_val ) ) { - si->si_scope = scopes[j].val; - break; - } - } - if ( BER_BVISNULL(&scopes[j].key) ) { + j = ldap_pvt_str2scope( val ); + if ( j < 0 ) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "Error: parse_syncrepl_line: " "unknown scope \"%s\"", val); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return -1; } + si->si_scope = j; si->si_got |= GOT_SCOPE; } else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR, STRLENOF( ATTRSONLYSTR ) ) ) @@ -4254,6 +4344,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: @@ -4271,24 +4363,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 ) { @@ -4307,6 +4410,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 @@ -4327,7 +4431,7 @@ add_syncrepl( si->si_cookieState = c->be->be_syncinfo->si_cookieState; - // add new syncrepl to end of list (same order as when deleting) + /* 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 { @@ -4336,6 +4440,7 @@ add_syncrepl( c->be->be_syncinfo = si; } + si->si_cookieState->cs_ref++; si->si_next = NULL; @@ -4346,7 +4451,7 @@ add_syncrepl( static void syncrepl_unparse( syncinfo_t *si, struct berval *bv ) { - struct berval bc, uri; + struct berval bc, uri, bs; char buf[BUFSIZ*2], *ptr; ber_len_t len; int i; @@ -4400,13 +4505,10 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv ) ptr = lutil_strcopy( ptr, si->si_logbase.bv_val ); *ptr++ = '"'; } - for (i=0; !BER_BVISNULL(&scopes[i].key);i++) { - if ( si->si_scope == scopes[i].val ) { - if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + scopes[i].key.bv_len ) return; - ptr = lutil_strcopy( ptr, " " SCOPESTR "=" ); - ptr = lutil_strcopy( ptr, scopes[i].key.bv_val ); - break; - } + if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) { + if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return; + ptr = lutil_strcopy( ptr, " " SCOPESTR "=" ); + ptr = lutil_strcopy( ptr, bs.bv_val ); } if ( si->si_attrsonly ) { if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return; @@ -4534,13 +4636,11 @@ 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 ) { @@ -4553,11 +4653,20 @@ syncrepl_config( ConfigArgs *c ) 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 ); @@ -4571,12 +4680,6 @@ syncrepl_config( ConfigArgs *c ) } if ( !c->be->be_syncinfo ) { SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK; - if ( cs && !isrunning ) { - ch_free( cs->cs_sids ); - ber_bvarray_free( cs->cs_vals ); - ldap_pvt_thread_mutex_destroy( &cs->cs_mutex ); - ch_free( cs ); - } } return 0; } -- 2.39.5