/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2003-2008 The OpenLDAP Foundation.
+ * Copyright 2003-2009 The OpenLDAP Foundation.
* Portions Copyright 2003 by IBM Corporation.
- * Portions Copyright 2003 by Howard Chu, Symas Corporation.
+ * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
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;
int si_refreshDone;
int si_syncdata;
int si_logstate;
+ int si_got;
ber_int_t si_msgid;
Avlnode *si_presentlist;
LDAP *si_ld;
{
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
- LDAPControl c[2], *ctrls[3];
+ LDAPControl c[3], *ctrls[4];
int rc;
int rhint;
char *base;
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,
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 */
syncinfo_t *si )
{
LDAPControl **rctrls = NULL;
- LDAPControl *rctrlp;
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
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;
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;
}
}
}
}
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
}
rc = 0;
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, "{" /*"}"*/);
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 )
"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:
if ( !BER_BVISNULL( &syncCookie.octet_str ) )
{
slap_parse_sync_cookie( &syncCookie, NULL );
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
}
/* Defaults to TRUE */
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 );
}
}
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 );
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:
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;
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;
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 )
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;
}
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 "
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 );
&slap_schema.si_ad_entryCSN->ad_cname ) )
{
slap_queue_csn( op, bvals );
+ do_graduate = 1;
}
ch_free( bvals );
}
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 );
"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:
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 );
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 );
Entry *new_entry;
struct berval dn;
struct berval ndn;
+ struct berval nnewSup;
int renamed; /* Was an existing entry renamed? */
+ int delOldRDN; /* Was old RDN deleted? */
Modifications **modlist; /* the modlist we received */
Modifications *mods; /* the modlist we compared */
+ Attribute *oldNattr; /* old naming attr */
+ AttributeDescription *oldDesc; /* for renames */
+ AttributeDescription *newDesc; /* for renames */
} dninfo;
/* return 1 if inserted, 0 otherwise */
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;
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 );
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 ) {
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;
}
op->o_req_dn = dni.dn;
op->o_req_ndn = dni.ndn;
if ( dni.renamed ) {
- struct berval noldp, newp, nnewp;
+ struct berval noldp, newp;
+ Modifications *mod, **modtail, **ml, *m2;
+ int i, got_replace = 0, just_rename = 0;
op->o_tag = LDAP_REQ_MODRDN;
dnRdn( &entry->e_name, &op->orr_newrdn );
dnRdn( &entry->e_nname, &op->orr_nnewrdn );
- dnParent( &dni.ndn, &noldp );
- dnParent( &entry->e_nname, &nnewp );
- if ( !dn_match( &noldp, &nnewp ) ) {
+ if ( !BER_BVISNULL( &dni.nnewSup )) {
dnParent( &entry->e_name, &newp );
op->orr_newSup = &newp;
- op->orr_nnewSup = &nnewp;
+ op->orr_nnewSup = &dni.nnewSup;
} else {
op->orr_newSup = NULL;
op->orr_nnewSup = NULL;
}
- /* Let the modify handler take care of deleting old RDNs */
- op->orr_deleteoldrdn = 0;
+ op->orr_deleteoldrdn = dni.delOldRDN;
op->orr_modlist = NULL;
if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
goto done;
}
+ /* Drop the RDN-related mods from this op, because their
+ * equivalents were just setup by slap_modrdn2mods.
+ *
+ * If delOldRDN is TRUE then we should see a delete modop
+ * for oldDesc. We might see a replace instead.
+ * delete with no values: therefore newDesc != oldDesc.
+ * if oldNattr had only one value, then Drop this op.
+ * delete with 1 value: can only be the oldRDN value. Drop op.
+ * delete with N values: Drop oldRDN value, keep remainder.
+ * replace with 1 value: if oldNattr had only one value and
+ * newDesc == oldDesc, Drop this op.
+ * Any other cases must be left intact.
+ *
+ * We should also see an add modop for newDesc. (But not if
+ * we got a replace modop due to delOldRDN.) If it has
+ * multiple values, we'll have to drop the new RDN value.
+ */
+ modtail = &op->orr_modlist;
+ if ( dni.delOldRDN ) {
+ for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
+ if ( (*ml)->sml_desc == dni.oldDesc ) {
+ mod = *ml;
+ if ( mod->sml_op == LDAP_MOD_REPLACE &&
+ dni.oldDesc != dni.newDesc ) {
+ /* This Replace is due to other Mods.
+ * Just let it ride.
+ */
+ continue;
+ }
+ if ( mod->sml_numvals <= 1 &&
+ dni.oldNattr->a_numvals == 1 &&
+ ( mod->sml_op == LDAP_MOD_DELETE ||
+ mod->sml_op == LDAP_MOD_REPLACE )) {
+ if ( mod->sml_op == LDAP_MOD_REPLACE )
+ got_replace = 1;
+ /* Drop this op */
+ *ml = mod->sml_next;
+ mod->sml_next = NULL;
+ slap_mods_free( mod, 1 );
+ break;
+ }
+ if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 )
+ continue;
+ for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
+ if ( m2->sml_desc == dni.oldDesc &&
+ m2->sml_op == LDAP_MOD_DELETE ) break;
+ }
+ for ( i=0; i<mod->sml_numvals; i++ ) {
+ if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
+ mod->sml_numvals--;
+ ch_free( mod->sml_values[i].bv_val );
+ mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
+ BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
+ if ( mod->sml_nvalues ) {
+ ch_free( mod->sml_nvalues[i].bv_val );
+ mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
+ BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
+ }
+ break;
+ }
+ }
+ if ( !mod->sml_numvals ) {
+ /* Drop this op */
+ *ml = mod->sml_next;
+ mod->sml_next = NULL;
+ slap_mods_free( mod, 1 );
+ }
+ break;
+ }
+ }
+ }
+ if ( !got_replace ) {
+ for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
+ if ( (*ml)->sml_desc == dni.newDesc ) {
+ mod = *ml;
+ if ( mod->sml_op != LDAP_MOD_ADD )
+ continue;
+ if ( mod->sml_numvals == 1 ) {
+ /* Drop this op */
+ *ml = mod->sml_next;
+ mod->sml_next = NULL;
+ slap_mods_free( mod, 1 );
+ break;
+ }
+ for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
+ if ( m2->sml_desc == dni.oldDesc &&
+ m2->sml_op == SLAP_MOD_SOFTADD ) break;
+ }
+ for ( i=0; i<mod->sml_numvals; i++ ) {
+ if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
+ mod->sml_numvals--;
+ ch_free( mod->sml_values[i].bv_val );
+ mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
+ BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
+ if ( mod->sml_nvalues ) {
+ ch_free( mod->sml_nvalues[i].bv_val );
+ mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
+ BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
/* RDNs must be NUL-terminated for back-ldap */
noldp = op->orr_newrdn;
ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
noldp = op->orr_nnewrdn;
ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
- /* Remove the CSN for now, only propagate the Modify */
- if ( syncCSN ) {
- slap_graduate_commit_csn( op );
+ /* Setup opattrs too */
+ {
+ static AttributeDescription *nullattr = NULL;
+ static AttributeDescription **const opattrs[] = {
+ &slap_schema.si_ad_entryCSN,
+ &slap_schema.si_ad_modifiersName,
+ &slap_schema.si_ad_modifyTimestamp,
+ &nullattr
+ };
+ AttributeDescription *opattr;
+ int i;
+
+ modtail = &m2;
+ /* pull mod off incoming modlist */
+ for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
+ for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
+ {
+ if ( (*ml)->sml_desc == opattr ) {
+ mod = *ml;
+ *ml = mod->sml_next;
+ mod->sml_next = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ break;
+ }
+ }
+ }
+ /* If there are still Modifications left, put the opattrs
+ * back, and let be_modify run. Otherwise, append the opattrs
+ * to the orr_modlist.
+ */
+ 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;
}
op->o_bd = si->si_wbe;
rc = op->o_bd->be_modrdn( op, &rs_modify );
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 still have other mods so just fallthru */
+ /* Renamed entries may still have other mods so just fallthru */
op->o_req_dn = entry->e_name;
op->o_req_ndn = entry->e_nname;
- if ( syncCSN ) {
+ /* 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;
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 {
+ } 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 :
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 ) {
break;
}
}
+ syncCSN = NULL;
op->o_bd = be;
}
goto done;
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; i<sc->numcsns; 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;
}
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 );
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;
ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+#ifdef CHECK_CSN
+ for ( i=0; i<syncCookie->numcsns; i++ ) {
+ assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i ));
+ }
+ for ( i=0; i<si->si_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 );
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; i<si->si_cookieState->cs_num; i++ ) {
+ assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
+ }
+#endif
+
return rc;
}
Attribute *old, *new;
struct berval old_rdn, new_rdn;
struct berval old_p, new_p;
- int is_ctx;
+ int is_ctx, new_sup = 0;
+
+ /* 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;
+ }
+ }
+ }
is_ctx = dn_match( &rs->sr_entry->e_nname,
&op->o_bd->be_nsuffix[0] );
dnParent( &rs->sr_entry->e_nname, &old_p );
dnParent( &dni->new_entry->e_nname, &new_p );
- if ( !dn_match( &old_rdn, &new_rdn ) ||
- ber_bvstrcasecmp( &old_p, &new_p ))
+ new_sup = !dn_match( &old_p, &new_p );
+ if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
{
- dni->renamed = 1;
+ struct berval oldRDN, oldVal;
+ AttributeDescription *ad = NULL;
+ int oldpos, newpos;
+ Attribute *a;
- /* A ModDN has happened, but other changes may have
- * occurred before we picked it up. So fallthru to
- * regular Modify processing.
+ dni->renamed = 1;
+ if ( new_sup )
+ dni->nnewSup = new_p;
+
+ /* See if the oldRDN was deleted */
+ dnRdn( &rs->sr_entry->e_nname, &oldRDN );
+ oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
+ oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
+ oldRDN.bv_val );
+ oldRDN.bv_len -= oldVal.bv_len + 1;
+ slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
+ dni->oldDesc = ad;
+ for ( oldpos=0, a=rs->sr_entry->e_attrs;
+ a && a->a_desc != ad; oldpos++, a=a->a_next );
+ dni->oldNattr = a;
+ for ( newpos=0, a=dni->new_entry->e_attrs;
+ a && a->a_desc != ad; newpos++, a=a->a_next );
+ if ( !a || oldpos != newpos || attr_valfind( a,
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_VALUE_OF_SYNTAX,
+ &oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
+ {
+ dni->delOldRDN = 1;
+ }
+ /* Get the newRDN's desc */
+ dnRdn( &dni->new_entry->e_nname, &oldRDN );
+ oldVal.bv_val = strchr(oldRDN.bv_val, '=');
+ oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val;
+ ad = NULL;
+ slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
+ dni->newDesc = ad;
+
+ /* A ModDN has happened, but in Refresh mode other
+ * changes may have occurred before we picked it up.
+ * So fallthru to regular Modify processing.
*/
}
modtail = &dni->mods;
ml = dni->modlist;
- /* 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;
- }
- }
-
/* 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
* 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 );
{
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;
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 );
}
}
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 );
#define MANAGEDSAITSTR "manageDSAit"
/* mandatory */
-#define GOT_ID 0x0001
-#define GOT_PROVIDER 0x0002
-#define GOT_BASE 0x0004
+enum {
+ GOT_RID = 0x00000001U,
+ GOT_PROVIDER = 0x00000002U,
+ GOT_SCHEMACHECKING = 0x00000004U,
+ GOT_FILTER = 0x00000008U,
+ GOT_SEARCHBASE = 0x00000010U,
+ GOT_SCOPE = 0x00000020U,
+ GOT_ATTRSONLY = 0x00000040U,
+ GOT_ATTRS = 0x00000080U,
+ GOT_TYPE = 0x00000100U,
+ GOT_INTERVAL = 0x00000200U,
+ GOT_RETRY = 0x00000400U,
+ GOT_SLIMIT = 0x00000800U,
+ GOT_TLIMIT = 0x00001000U,
+ GOT_SYNCDATA = 0x00002000U,
+ GOT_LOGBASE = 0x00004000U,
+ GOT_LOGFILTER = 0x00008000U,
+ GOT_EXATTRS = 0x00010000U,
+ GOT_MANAGEDSAIT = 0x00020000U,
+ GOT_BINDCONF = 0x00040000U,
/* check */
-#define GOT_ALL (GOT_ID|GOT_PROVIDER|GOT_BASE)
+ GOT_REQUIRED = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
+};
static struct {
struct berval key;
{ BER_BVNULL, 0 }
};
+static int
+parse_syncrepl_retry(
+ ConfigArgs *c,
+ char *arg,
+ syncinfo_t *si )
+{
+ char **retry_list;
+ int j, k, n;
+ int use_default = 0;
+
+ char *val = arg + STRLENOF( RETRYSTR "=" );
+ if ( strcasecmp( val, "undefined" ) == 0 ) {
+ val = "3600 +";
+ use_default = 1;
+ }
+
+ retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
+ retry_list[0] = NULL;
+
+ slap_str2clist( &retry_list, val, " ,\t" );
+
+ for ( k = 0; retry_list && retry_list[k]; k++ ) ;
+ n = k / 2;
+ if ( k % 2 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Error: incomplete syncrepl retry list" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ for ( k = 0; retry_list && retry_list[k]; k++ ) {
+ ch_free( retry_list[k] );
+ }
+ ch_free( retry_list );
+ return 1;
+ }
+ si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
+ si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
+ si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
+ for ( j = 0; j < n; j++ ) {
+ unsigned long t;
+ if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Error: invalid retry interval \"%s\" (#%d)",
+ retry_list[j*2], j );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ /* do some cleanup */
+ return 1;
+ }
+ si->si_retryinterval[j] = (time_t)t;
+ if ( *retry_list[j*2+1] == '+' ) {
+ si->si_retrynum_init[j] = RETRYNUM_FOREVER;
+ si->si_retrynum[j] = RETRYNUM_FOREVER;
+ j++;
+ break;
+ } else {
+ if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
+ || si->si_retrynum_init[j] <= 0 )
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Error: invalid initial retry number \"%s\" (#%d)",
+ retry_list[j*2+1], j );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ /* do some cleanup */
+ return 1;
+ }
+ if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
+ || si->si_retrynum[j] <= 0 )
+ {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Error: invalid retry number \"%s\" (#%d)",
+ retry_list[j*2+1], j );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ /* do some cleanup */
+ return 1;
+ }
+ }
+ }
+ si->si_retrynum_init[j] = RETRYNUM_TAIL;
+ si->si_retrynum[j] = RETRYNUM_TAIL;
+ si->si_retryinterval[j] = 0;
+
+ for ( k = 0; retry_list && retry_list[k]; k++ ) {
+ ch_free( retry_list[k] );
+ }
+ ch_free( retry_list );
+ if ( !use_default ) {
+ si->si_got |= GOT_RETRY;
+ }
+
+ return 0;
+}
+
static int
parse_syncrepl_line(
ConfigArgs *c,
syncinfo_t *si )
{
- int gots = 0;
int i;
char *val;
}
si->si_rid = tmp;
sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
- gots |= GOT_ID;
+ si->si_got |= GOT_RID;
} else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
STRLENOF( PROVIDERSTR "=" ) ) )
{
val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
- gots |= GOT_PROVIDER;
+ si->si_got |= GOT_PROVIDER;
} else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
STRLENOF( SCHEMASTR "=" ) ) )
{
} else {
si->si_schemachecking = 1;
}
+ si->si_got |= GOT_SCHEMACHECKING;
} else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
STRLENOF( FILTERSTR "=" ) ) )
{
if ( si->si_filterstr.bv_val )
ch_free( si->si_filterstr.bv_val );
ber_str2bv( val, 0, 1, &si->si_filterstr );
+ si->si_got |= GOT_FILTER;
} else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
STRLENOF( LOGFILTERSTR "=" ) ) )
{
if ( si->si_logfilterstr.bv_val )
ch_free( si->si_logfilterstr.bv_val );
ber_str2bv( val, 0, 1, &si->si_logfilterstr );
+ si->si_got |= GOT_LOGFILTER;
} else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
STRLENOF( SEARCHBASESTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
- gots |= GOT_BASE;
+ si->si_got |= GOT_SEARCHBASE;
} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
STRLENOF( LOGBASESTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_got |= GOT_LOGBASE;
} else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
STRLENOF( SCOPESTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_got |= GOT_SCOPE;
} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
STRLENOF( ATTRSONLYSTR ) ) )
{
si->si_attrsonly = 1;
+ si->si_got |= GOT_ATTRSONLY;
} else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
STRLENOF( ATTRSSTR "=" ) ) )
{
return -1;
}
}
+ si->si_got |= GOT_ATTRS;
} else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
STRLENOF( EXATTRSSTR "=" ) ) )
{
return -1;
}
}
+ si->si_got |= GOT_EXATTRS;
} else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
STRLENOF( TYPESTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_got |= GOT_TYPE;
} else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
STRLENOF( INTERVALSTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_got |= GOT_INTERVAL;
} else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
STRLENOF( RETRYSTR "=" ) ) )
{
- char **retry_list;
- int j, k, n;
-
- val = c->argv[ i ] + STRLENOF( RETRYSTR "=" );
- retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
- retry_list[0] = NULL;
-
- slap_str2clist( &retry_list, val, " ,\t" );
-
- for ( k = 0; retry_list && retry_list[k]; k++ ) ;
- n = k / 2;
- if ( k % 2 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "Error: incomplete syncrepl retry list" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
- for ( k = 0; retry_list && retry_list[k]; k++ ) {
- ch_free( retry_list[k] );
- }
- ch_free( retry_list );
+ if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) {
return 1;
}
- si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
- si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
- si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
- for ( j = 0; j < n; j++ ) {
- unsigned long t;
- if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "Error: invalid retry interval \"%s\" (#%d)",
- retry_list[j*2], j );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
- /* do some cleanup */
- return 1;
- }
- si->si_retryinterval[j] = (time_t)t;
- if ( *retry_list[j*2+1] == '+' ) {
- si->si_retrynum_init[j] = RETRYNUM_FOREVER;
- si->si_retrynum[j] = RETRYNUM_FOREVER;
- j++;
- break;
- } else {
- if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
- || si->si_retrynum_init[j] <= 0 )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "Error: invalid initial retry number \"%s\" (#%d)",
- retry_list[j*2+1], j );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
- /* do some cleanup */
- return 1;
- }
- if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
- || si->si_retrynum[j] <= 0 )
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "Error: invalid retry number \"%s\" (#%d)",
- retry_list[j*2+1], j );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
- /* do some cleanup */
- return 1;
- }
- }
- }
- si->si_retrynum_init[j] = RETRYNUM_TAIL;
- si->si_retrynum[j] = RETRYNUM_TAIL;
- si->si_retryinterval[j] = 0;
-
- for ( k = 0; retry_list && retry_list[k]; k++ ) {
- ch_free( retry_list[k] );
- }
- ch_free( retry_list );
} else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
STRLENOF( MANAGEDSAITSTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return 1;
}
+ si->si_got |= GOT_MANAGEDSAIT;
} else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
STRLENOF( SLIMITSTR "=") ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return 1;
}
+ si->si_got |= GOT_SLIMIT;
} else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
STRLENOF( TLIMITSTR "=" ) ) )
{
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return 1;
}
+ si->si_got |= GOT_TLIMIT;
} else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
STRLENOF( SYNCDATASTR "=" ) ) )
{
val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
si->si_syncdata = verb_to_mask( val, datamodes );
+ si->si_got |= GOT_SYNCDATA;
} else if ( bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: parse_syncrepl_line: "
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_got |= GOT_BINDCONF;
}
- if ( gots != GOT_ALL ) {
+ if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
- gots & GOT_ID ? "" : " "IDSTR,
- gots & GOT_PROVIDER ? "" : " "PROVIDERSTR,
- gots & GOT_BASE ? "" : " "SEARCHBASESTR );
+ si->si_got & GOT_RID ? "" : " "IDSTR,
+ si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR,
+ si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ if ( !( si->si_got & GOT_RETRY ) ) {
+ Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n",
+ si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
+ if ( si->si_retryinterval == NULL ) {
+ if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) {
+ return 1;
+ }
+ }
+ }
+
return 0;
}
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;
}
}
INTERVALSTR, dd, hh, mm, ss );
if ( len >= WHATSLEFT ) return;
ptr += len;
- } else if ( si->si_retryinterval ) {
+ }
+
+ if ( si->si_got & GOT_RETRY ) {
const char *space = "";
if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
}
if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
*ptr++ = '"';
+ } else {
+ ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
}
if ( si->si_slimit ) {
}
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 ) {
+ isrunning = 1;
+ /* If there's a persistent connection, we don't
+ * know if it's already got a thread queued.
+ * so defer the free, but reschedule the task.
+ * If there's a connection thread queued, it
+ * will cleanup as necessary. If not, then the
+ * runqueue task will cleanup.
+ */
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ if ( !ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re )) {
+ si->si_re->interval.tv_sec = 0;
+ ldap_pvt_runqueue_resched( &slapd_rq, si->si_re, 0 );
+ si->si_re->interval.tv_sec = si->si_interval;
+ }
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+ }
+ 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 );
}
}
}
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;
}