/* $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;
static int syncuuid_cmp( const void *, const void * );
static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
-static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct berval * );
+static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
static int syncrepl_message_to_op(
syncinfo_t *, Operation *, LDAPMessage * );
static int syncrepl_message_to_entry(
{
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
- LDAPControl c[2], *ctrls[3];
+ LDAPControl c[3], *ctrls[4];
int rc;
int rhint;
char *base;
abs(si->si_type), rhint );
}
- if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == LBER_ERROR ) {
+ if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
ber_free_buf( ber );
return rc;
}
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,
return rc;
}
+static int
+check_syncprov(
+ Operation *op,
+ syncinfo_t *si )
+{
+ AttributeName at[2];
+ Attribute a = {0};
+ Entry e = {0};
+ SlapReply rs = {0};
+ int i, j, changed = 0;
+
+ /* Look for contextCSN from syncprov overlay. If
+ * there's no overlay, this will be a no-op. That means
+ * this is a pure consumer, so local changes will not be
+ * allowed, and all changes will already be reflected in
+ * the cookieState.
+ */
+ a.a_desc = slap_schema.si_ad_contextCSN;
+ e.e_attrs = &a;
+ e.e_name = op->o_bd->be_suffix[0];
+ e.e_nname = op->o_bd->be_nsuffix[0];
+ at[0].an_name = a.a_desc->ad_cname;
+ at[0].an_desc = a.a_desc;
+ BER_BVZERO( &at[1].an_name );
+ rs.sr_entry = &e;
+ rs.sr_flags = REP_ENTRY_MODIFIABLE;
+ rs.sr_attrs = at;
+ op->o_req_dn = e.e_name;
+ op->o_req_ndn = e.e_nname;
+
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ i = backend_operational( op, &rs );
+ if ( i == LDAP_SUCCESS && a.a_nvals ) {
+ int num = a.a_numvals;
+ /* check for differences */
+ if ( num != si->si_cookieState->cs_num ) {
+ changed = 1;
+ } else {
+ for ( i=0; i<num; i++ ) {
+ if ( ber_bvcmp( &a.a_nvals[i],
+ &si->si_cookieState->cs_vals[i] )) {
+ changed = 1;
+ break;
+ }
+ }
+ }
+ if ( changed ) {
+ ber_bvarray_free( si->si_cookieState->cs_vals );
+ ch_free( si->si_cookieState->cs_sids );
+ si->si_cookieState->cs_num = num;
+ si->si_cookieState->cs_vals = a.a_nvals;
+ si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
+ num, NULL );
+ si->si_cookieState->cs_age++;
+ } else {
+ ber_bvarray_free( a.a_nvals );
+ }
+ ber_bvarray_free( a.a_vals );
+ }
+ /* See if the cookieState has changed due to anything outside
+ * this particular consumer. That includes other consumers in
+ * the same context, or local changes detected above.
+ */
+ if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
+ si->si_cookieState->cs_age ) {
+ if ( !si->si_syncCookie.numcsns ) {
+ ber_bvarray_free( si->si_syncCookie.ctxcsn );
+ ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+ si->si_cookieState->cs_vals, NULL );
+ changed = 1;
+ } else {
+ for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
+ /* bogus, just dup everything */
+ if ( si->si_syncCookie.sids[i] == -1 ) {
+ ber_bvarray_free( si->si_syncCookie.ctxcsn );
+ ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+ si->si_cookieState->cs_vals, NULL );
+ changed = 1;
+ break;
+ }
+ for (j=0; j<si->si_cookieState->cs_num; j++) {
+ if ( si->si_syncCookie.sids[i] !=
+ si->si_cookieState->cs_sids[j] )
+ continue;
+ if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
+ &si->si_cookieState->cs_vals[j] ))
+ break;
+ ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
+ &si->si_cookieState->cs_vals[j] );
+ changed = 1;
+ break;
+ }
+ }
+ }
+ }
+ if ( changed ) {
+ si->si_cookieAge = si->si_cookieState->cs_age;
+ ch_free( si->si_syncCookie.octet_str.bv_val );
+ slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
+ si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
+ si->si_syncCookie.sid );
+ }
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ return changed;
+}
+
static int
do_syncrep1(
Operation *op,
op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
}
#endif /* HAVE_TLS */
- ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
+ {
+ ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
+ to use sasl_ssf_t but currently uses ber_len_t */
+ ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf );
+ op->o_sasl_ssf = ssf;
+ }
op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
? op->o_sasl_ssf : op->o_tls_ssf;
ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
+ 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 */
+ si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
+ slap_serverID : -1;
+
/* We've just started up, or the remote server hasn't sent us
* any meaningful state.
*/
if ( BER_BVISNULL( &si->si_syncCookie.octet_str ) ) {
int i;
- si->si_syncCookie.rid = si->si_rid;
- si->si_syncCookie.sid = SLAP_SINGLE_SHADOW( si->si_be ) ? -1 :
- slap_serverID;
-
LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
if ( si->si_rid == sc->rid ) {
cmdline_cookie_found = 1;
si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
si->si_syncCookie.sid );
} else {
- AttributeName at[2];
- Attribute a = {0};
- Entry e = {0};
- SlapReply rs = {0};
- int i, j, changed = 0;
-
- /* Look for contextCSN from syncprov overlay. If
- * there's no overlay, this will be a no-op. That means
- * this is a pure consumer, so local changes will not be
- * allowed, and all changes will already be reflected in
- * the cookieState.
- */
- a.a_desc = slap_schema.si_ad_contextCSN;
- e.e_attrs = &a;
- e.e_name = si->si_wbe->be_suffix[0];
- e.e_nname = si->si_wbe->be_nsuffix[0];
- rs.sr_entry = &e;
- rs.sr_flags = REP_ENTRY_MODIFIABLE;
- at[0].an_name = a.a_desc->ad_cname;
- at[0].an_desc = a.a_desc;
- BER_BVZERO( &at[1].an_name );
- op->o_req_dn = e.e_name;
- op->o_req_ndn = e.e_nname;
-
- ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
- rc = backend_operational( op, &rs );
- if ( rc == LDAP_SUCCESS && a.a_vals ) {
- int num = a.a_numvals;
- /* check for differences */
- if ( num != si->si_cookieState->cs_num ) {
- changed = 1;
- } else {
- for ( i=0; i<num; i++ ) {
- if ( ber_bvcmp( &a.a_vals[i],
- &si->si_cookieState->cs_vals[i] )) {
- changed =1;
- break;
- }
- }
- }
- if ( changed ) {
- ber_bvarray_free( si->si_cookieState->cs_vals );
- ch_free( si->si_cookieState->cs_sids );
- si->si_cookieState->cs_num = num;
- si->si_cookieState->cs_vals = a.a_vals;
- si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_vals,
- num, NULL );
- si->si_cookieState->cs_age++;
- } else {
- ber_bvarray_free( a.a_vals );
- }
- changed = 0;
- }
- /* See if the cookieState has changed due to anything outside
- * this particular consumer. That includes other consumers in
- * the same context, or local changes detected above.
- */
- if ( si->si_cookieState->cs_num > 1 && si->si_cookieAge !=
- si->si_cookieState->cs_age ) {
-
- for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
- /* bogus, just dup everything */
- if ( si->si_syncCookie.sids[i] == -1 ) {
- ber_bvarray_free( si->si_syncCookie.ctxcsn );
- ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
- si->si_cookieState->cs_vals, NULL );
- changed = 1;
- break;
- }
- for (j=0; j<si->si_cookieState->cs_num; j++) {
- if ( si->si_syncCookie.sids[i] !=
- si->si_cookieState->cs_sids[j] )
- continue;
- if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
- &si->si_cookieState->cs_vals[j] ))
- break;
- ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
- &si->si_cookieState->cs_vals[j] );
- changed = 1;
- break;
- }
- }
- if ( changed ) {
- ch_free( si->si_syncCookie.octet_str.bv_val );
- slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
- si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
- SLAP_SINGLE_SHADOW( si->si_be ) ? -1 : slap_serverID );
- }
- }
- ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ /* Look for contextCSN from syncprov overlay. */
+ check_syncprov( op, si );
}
si->si_refreshDone = 0;
return -1;
}
- for (i=0; !BER_BVISNULL( &sc1->ctxcsn[i] ); i++) {
- for (j=0; !BER_BVISNULL( &sc2->ctxcsn[j] ); j++) {
+ for (j=0; j<sc2->numcsns; j++) {
+ for (i=0; i<sc1->numcsns; i++) {
if ( sc1->sids[i] != sc2->sids[j] )
continue;
value_match( &match, slap_schema.si_ad_entryCSN,
slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
- &sc1->ctxcsn[i], &sc2->ctxcsn[i], &text );
+ &sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
if ( match < 0 ) {
*which = j;
return match;
}
break;
}
+ if ( i == sc1->numcsns ) {
+ /* sc2 has a sid sc1 lacks */
+ *which = j;
+ return -1;
+ }
}
return match;
}
+#define SYNC_PAUSED -3
+
static int
do_syncrep2(
Operation *op,
syncinfo_t *si )
{
LDAPControl **rctrls = NULL;
- LDAPControl *rctrlp;
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
- LDAPMessage *res = NULL;
LDAPMessage *msg = NULL;
char *retoid = NULL;
}
while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
- tout_p, &res ) ) > 0 )
+ tout_p, &msg ) ) > 0 )
{
+ LDAPControl *rctrlp = NULL;
+
if ( slapd_shutdown ) {
rc = -2;
goto done;
}
- for( msg = ldap_first_message( si->si_ld, res );
- msg != NULL;
- msg = ldap_next_message( si->si_ld, msg ) )
- {
- if ( slapd_shutdown ) {
- rc = -2;
- goto done;
- }
- switch( ldap_msgtype( msg ) ) {
- 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 */
- 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 );
- rc = -1;
- goto done;
- }
- }
- if ( rctrlp == NULL ) {
+ switch( ldap_msgtype( msg ) ) {
+ case LDAP_RES_SEARCH_ENTRY:
+ ldap_get_entry_controls( si->si_ld, msg, &rctrls );
+ /* we can't work without the control */
+ 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 without "
+ "got search entry with multiple "
"Sync State control\n", si->si_ridtxt, 0, 0 );
+ ldap_controls_free( rctrls );
rc = -1;
goto done;
}
- ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
- ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
- /* FIXME: what if syncUUID is NULL or empty?
- * (happens with back-sql...) */
- if ( BER_BVISEMPTY( &syncUUID ) ) {
+ }
+ if ( rctrlp == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+ "got search entry without "
+ "Sync State control\n", si->si_ridtxt, 0, 0 );
+ rc = -1;
+ goto done;
+ }
+ ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+ ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
+ /* FIXME: what if syncUUID is NULL or empty?
+ * (happens with back-sql...) */
+ if ( BER_BVISEMPTY( &syncUUID ) ) {
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+ "got empty syncUUID with LDAP_SYNC_%s\n",
+ si->si_ridtxt,
+ syncrepl_state2str( syncstate ), 0 );
+ ldap_controls_free( rctrls );
+ rc = -1;
+ goto done;
+ }
+ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
+ ber_scanf( ber, /*"{"*/ "m}", &cookie );
+
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 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 );
+ if ( syncCookie.ctxcsn ) {
+ int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
+ for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+ if ( si->si_cookieState->cs_sids[i] == sid &&
+ ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
+ si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
+ ldap_controls_free( rctrls );
+ rc = 0;
+ goto done;
+ }
+ }
+ }
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
+ }
+ }
+ rc = 0;
+ if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
+ modlist = NULL;
+ if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
+ syncCookie.ctxcsn )
+ {
+ rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ } else switch ( rc ) {
+ case LDAP_ALREADY_EXISTS:
+ case LDAP_NO_SUCH_OBJECT:
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ rc = LDAP_SYNC_REFRESH_REQUIRED;
+ si->si_logstate = SYNCLOG_FALLBACK;
+ ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+ break;
+ default:
+ break;
+ }
+ } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
+ &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+ {
+ if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
+ syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
+ syncCookie.ctxcsn )
+ {
+ rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ }
+ }
+ ldap_controls_free( rctrls );
+ if ( modlist ) {
+ slap_mods_free( modlist, 1 );
+ }
+ if ( rc )
+ goto done;
+ break;
+
+ case LDAP_RES_SEARCH_REFERENCE:
+ Debug( LDAP_DEBUG_ANY,
+ "do_syncrep2: %s reference received error\n",
+ si->si_ridtxt, 0, 0 );
+ break;
+
+ case LDAP_RES_SEARCH_RESULT:
+ Debug( LDAP_DEBUG_SYNC,
+ "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
+ si->si_ridtxt, 0, 0 );
+ ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
+ &rctrls, 0 );
+#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
+ if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
+ /* map old result code to registered code */
+ err = LDAP_SYNC_REFRESH_REQUIRED;
+ }
+#endif
+ if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
+ if ( si->si_logstate == SYNCLOG_LOGGING ) {
+ si->si_logstate = SYNCLOG_FALLBACK;
+ }
+ rc = err;
+ goto done;
+ }
+ if ( err ) {
+ Debug( LDAP_DEBUG_ANY,
+ "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
+ si->si_ridtxt, err, ldap_err2string( err ) );
+ }
+ 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_DONE, rctrls, &next );
+ if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
+ {
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
- "got empty syncUUID with LDAP_SYNC_%s\n",
- si->si_ridtxt,
- syncrepl_state2str( syncstate ), 0 );
+ "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_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
- ber_scanf( ber, /*"{"*/ "m}", &cookie );
+ ber_scanf( ber, "m", &cookie );
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
- ber_dupbv( &syncCookie.octet_str, &cookie );
+ ber_dupbv( &syncCookie.octet_str, &cookie);
}
if ( !BER_BVISNULL( &syncCookie.octet_str ) )
{
slap_parse_sync_cookie( &syncCookie, NULL );
- if ( syncCookie.ctxcsn ) {
- int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
- for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
- if ( si->si_cookieState->cs_sids[i] == sid &&
- ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
- si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
- ldap_controls_free( rctrls );
- rc = 0;
- goto done;
- }
- }
- }
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
}
- rc = 0;
- if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
- modlist = NULL;
- if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
- syncCookie.ctxcsn )
- {
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
- } else if ( rc == LDAP_NO_SUCH_OBJECT ) {
- rc = LDAP_SYNC_REFRESH_REQUIRED;
- si->si_logstate = SYNCLOG_FALLBACK;
- ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
- }
- } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
- &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
{
- if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
- syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
- syncCookie.ctxcsn )
- {
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
- }
+ ber_scanf( ber, "b", &refreshDeletes );
}
+ ber_scanf( ber, /*"{"*/ "}" );
+ }
+ if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+ }
+ if ( !syncCookie.ctxcsn ) {
+ match = 1;
+ } else if ( !syncCookie_req.ctxcsn ) {
+ match = -1;
+ m = 0;
+ } else {
+ match = compare_csns( &syncCookie_req, &syncCookie, &m );
+ }
+ if ( rctrls ) {
ldap_controls_free( rctrls );
- if ( modlist ) {
- slap_mods_free( modlist, 1 );
+ }
+ if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
+ /* FIXME : different error behaviors according to
+ * 1) err code : LDAP_BUSY ...
+ * 2) on err policy : stop service, stop sync, retry
+ */
+ if ( refreshDeletes == 0 && match < 0 &&
+ err == LDAP_SUCCESS &&
+ syncCookie_req.numcsns == syncCookie.numcsns )
+ {
+ syncrepl_del_nonpresent( op, si, NULL,
+ &syncCookie, m );
+ } else {
+ avl_free( si->si_presentlist, ch_free );
+ si->si_presentlist = NULL;
}
- if ( rc )
- goto done;
- break;
-
- case LDAP_RES_SEARCH_REFERENCE:
- Debug( LDAP_DEBUG_ANY,
- "do_syncrep2: %s reference received error\n",
- si->si_ridtxt, 0, 0 );
- break;
+ }
+ if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
+ {
+ rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ }
+ if ( err == LDAP_SUCCESS
+ && si->si_logstate == SYNCLOG_FALLBACK ) {
+ si->si_logstate = SYNCLOG_LOGGING;
+ rc = LDAP_SYNC_REFRESH_REQUIRED;
+ } else {
+ rc = -2;
+ }
+ goto done;
+ break;
- case LDAP_RES_SEARCH_RESULT:
- Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
- si->si_ridtxt, 0, 0 );
- ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
- &rctrls, 0 );
-#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
- if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
- /* map old result code to registered code */
- err = LDAP_SYNC_REFRESH_REQUIRED;
- }
-#endif
- if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
- if ( si->si_logstate == SYNCLOG_LOGGING ) {
- si->si_logstate = SYNCLOG_FALLBACK;
+ case LDAP_RES_INTERMEDIATE:
+ rc = ldap_parse_intermediate( si->si_ld, msg,
+ &retoid, &retdata, NULL, 0 );
+ if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
+ ber_init2( ber, retdata, LBER_USE_DER );
+
+ switch ( si_tag = ber_peek_tag( ber, &len ) ) {
+ ber_tag_t tag;
+ case LDAP_TAG_SYNC_NEW_COOKIE:
+ Debug( LDAP_DEBUG_SYNC,
+ "do_syncrep2: %s %s - %s\n",
+ si->si_ridtxt,
+ "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 );
}
- rc = err;
- goto done;
- }
- if ( rctrls ) {
- rctrlp = *rctrls;
- ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+ 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:
+ Debug( LDAP_DEBUG_SYNC,
+ "do_syncrep2: %s %s - %s\n",
+ si->si_ridtxt,
+ "LDAP_RES_INTERMEDIATE",
+ si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
+ "REFRESH_PRESENT" : "REFRESH_DELETE" );
+ if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
+ si->si_refreshDelete = 1;
+ } else {
+ si->si_refreshPresent = 1;
+ }
+ ber_scanf( ber, "t{" /*"}"*/, &tag );
+ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
+ {
+ ber_scanf( ber, "m", &cookie );
+
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
- ber_scanf( ber, "{" /*"}"*/);
- if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
+ 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;
+ }
+ }
+ /* Defaults to TRUE */
+ if ( ber_peek_tag( ber, &len ) ==
+ LDAP_TAG_REFRESHDONE )
+ {
+ ber_scanf( ber, "b", &si->si_refreshDone );
+ } else
+ {
+ si->si_refreshDone = 1;
+ }
+ ber_scanf( ber, /*"{"*/ "}" );
+ break;
+ case LDAP_TAG_SYNC_ID_SET:
+ Debug( LDAP_DEBUG_SYNC,
+ "do_syncrep2: %s %s - %s\n",
+ si->si_ridtxt,
+ "LDAP_RES_INTERMEDIATE",
+ "SYNC_ID_SET" );
+ ber_scanf( ber, "t{" /*"}"*/, &tag );
+ if ( ber_peek_tag( ber, &len ) ==
+ LDAP_TAG_SYNC_COOKIE )
+ {
ber_scanf( ber, "m", &cookie );
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
- ber_dupbv( &syncCookie.octet_str, &cookie);
+ 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;
+ compare_csns( &syncCookie_req, &syncCookie, &m );
}
}
- if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
+ if ( ber_peek_tag( ber, &len ) ==
+ LDAP_TAG_REFRESHDELETES )
{
ber_scanf( ber, "b", &refreshDeletes );
}
+ ber_scanf( ber, "[W]", &syncUUIDs );
ber_scanf( ber, /*"{"*/ "}" );
+ if ( refreshDeletes ) {
+ syncrepl_del_nonpresent( op, si, syncUUIDs,
+ &syncCookie, m );
+ ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
+ } else {
+ int i;
+ for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
+ (void)avl_presentlist_insert( si, &syncUUIDs[i] );
+ slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+ }
+ slap_sl_free( syncUUIDs, op->o_tmpmemctx );
+ }
+ slap_sync_cookie_free( &syncCookie, 0 );
+ break;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
+ si->si_ridtxt, (long) si_tag, 0 );
+ ldap_memfree( retoid );
+ ber_bvfree( retdata );
+ continue;
+ }
+
+ if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
}
if ( !syncCookie.ctxcsn ) {
match = 1;
} else {
match = compare_csns( &syncCookie_req, &syncCookie, &m );
}
- if ( rctrls ) {
- ldap_controls_free( rctrls );
- }
- if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
- /* FIXME : different error behaviors according to
- * 1) err code : LDAP_BUSY ...
- * 2) on err policy : stop service, stop sync, retry
- */
- if ( refreshDeletes == 0 && match < 0 &&
- err == LDAP_SUCCESS )
- {
- syncrepl_del_nonpresent( op, si, NULL,
- &syncCookie.ctxcsn[m] );
- } else {
- avl_free( si->si_presentlist, ch_free );
- si->si_presentlist = NULL;
- }
- }
- if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
- {
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
- }
- if ( err == LDAP_SUCCESS
- && si->si_logstate == SYNCLOG_FALLBACK ) {
- si->si_logstate = SYNCLOG_LOGGING;
- rc = LDAP_SYNC_REFRESH_REQUIRED;
- } else {
- rc = -2;
- }
- goto done;
- break;
-
- case LDAP_RES_INTERMEDIATE:
- rc = ldap_parse_intermediate( si->si_ld, msg,
- &retoid, &retdata, NULL, 0 );
- if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
- ber_init2( ber, retdata, LBER_USE_DER );
-
- switch ( si_tag = ber_peek_tag( ber, &len ) ) {
- ber_tag_t tag;
- case LDAP_TAG_SYNC_NEW_COOKIE:
- Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: %s %s - %s\n",
- si->si_ridtxt,
- "LDAP_RES_INTERMEDIATE",
- "NEW_COOKIE" );
- ber_scanf( ber, "tm", &tag, &cookie );
- break;
- case LDAP_TAG_SYNC_REFRESH_DELETE:
- case LDAP_TAG_SYNC_REFRESH_PRESENT:
- Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: %s %s - %s\n",
- si->si_ridtxt,
- "LDAP_RES_INTERMEDIATE",
- si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
- "REFRESH_PRESENT" : "REFRESH_DELETE" );
- if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
- si->si_refreshDelete = 1;
- } else {
- si->si_refreshPresent = 1;
- }
- ber_scanf( ber, "t{" /*"}"*/, &tag );
- if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
- {
- ber_scanf( ber, "m", &cookie );
-
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 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 );
- }
- }
- /* Defaults to TRUE */
- if ( ber_peek_tag( ber, &len ) ==
- LDAP_TAG_REFRESHDONE )
- {
- ber_scanf( ber, "b", &si->si_refreshDone );
- } else
- {
- si->si_refreshDone = 1;
- }
- ber_scanf( ber, /*"{"*/ "}" );
- break;
- case LDAP_TAG_SYNC_ID_SET:
- Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: %s %s - %s\n",
- si->si_ridtxt,
- "LDAP_RES_INTERMEDIATE",
- "SYNC_ID_SET" );
- ber_scanf( ber, "t{" /*"}"*/, &tag );
- if ( ber_peek_tag( ber, &len ) ==
- LDAP_TAG_SYNC_COOKIE )
- {
- ber_scanf( ber, "m", &cookie );
-
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 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 );
- compare_csns( &syncCookie_req, &syncCookie, &m );
- }
- }
- if ( ber_peek_tag( ber, &len ) ==
- LDAP_TAG_REFRESHDELETES )
- {
- ber_scanf( ber, "b", &refreshDeletes );
- }
- ber_scanf( ber, "[W]", &syncUUIDs );
- ber_scanf( ber, /*"{"*/ "}" );
- if ( refreshDeletes ) {
- syncrepl_del_nonpresent( op, si, syncUUIDs,
- &syncCookie.ctxcsn[m] );
- ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
- } else {
- int i;
- for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
- (void)avl_presentlist_insert( si, &syncUUIDs[i] );
- slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
- }
- slap_sl_free( syncUUIDs, op->o_tmpmemctx );
- }
- slap_sync_cookie_free( &syncCookie, 0 );
- break;
- default:
- Debug( LDAP_DEBUG_ANY,
- "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
- si->si_ridtxt, (long) si_tag, 0 );
- ldap_memfree( retoid );
- ber_bvfree( retdata );
- continue;
+ 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 );
}
- if ( !syncCookie.ctxcsn ) {
- match = 1;
- } else if ( !syncCookie_req.ctxcsn ) {
- match = -1;
- m = 0;
- } else {
- match = compare_csns( &syncCookie_req, &syncCookie, &m );
+ if ( syncCookie.ctxcsn )
+ {
+ rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
}
+ }
- if ( match < 0 ) {
- if ( si->si_refreshPresent == 1 ) {
- syncrepl_del_nonpresent( op, si, NULL,
- &syncCookie.ctxcsn[m] );
- }
-
- if ( syncCookie.ctxcsn )
- {
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
- }
- }
-
- ldap_memfree( retoid );
- ber_bvfree( retdata );
- break;
-
- } else {
- Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
- "unknown intermediate response (%d)\n",
- si->si_ridtxt, rc, 0 );
- ldap_memfree( retoid );
- ber_bvfree( retdata );
- break;
- }
+ ldap_memfree( retoid );
+ ber_bvfree( retdata );
break;
- default:
+ } else {
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
- "unknown message (0x%02lx)\n",
- si->si_ridtxt,
- (unsigned long)ldap_msgtype( msg ), 0 );
+ "unknown intermediate response (%d)\n",
+ si->si_ridtxt, rc, 0 );
+ ldap_memfree( retoid );
+ ber_bvfree( retdata );
break;
-
- }
- if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
- slap_sync_cookie_free( &syncCookie_req, 0 );
- slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
- slap_sync_cookie_free( &syncCookie, 0 );
}
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+ "unknown message (0x%02lx)\n",
+ si->si_ridtxt,
+ (unsigned long)ldap_msgtype( msg ), 0 );
+ break;
+
+ }
+ if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
+ slap_sync_cookie_free( &syncCookie, 0 );
+ }
+ ldap_msgfree( msg );
+ msg = NULL;
+ if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
+ slap_sync_cookie_free( &syncCookie, 0 );
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ return SYNC_PAUSED;
}
- ldap_msgfree( res );
- res = NULL;
}
if ( rc == -1 ) {
slap_sync_cookie_free( &syncCookie, 0 );
slap_sync_cookie_free( &syncCookie_req, 0 );
- if ( res ) ldap_msgfree( res );
+ if ( msg ) ldap_msgfree( msg );
if ( rc && rc != LDAP_SYNC_REFRESH_REQUIRED && si->si_ld ) {
if ( si->si_conn ) {
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 );
+
+ /* 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();
+ }
- /* Don't wait around if there's a previous session still running */
- if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex ))
- return NULL;
+ 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;
- op->o_bd = be = si->si_be;
- op->o_dn = op->o_bd->be_rootdn;
- op->o_ndn = op->o_bd->be_rootndn;
- if ( !si->si_schemachecking )
- op->o_no_schema_check = 1;
-
- /* If we're glued, send writes through the glue parent */
+ be = si->si_be;
+
+ /* Coordinate contextCSN updates with any syncprov overlays
+ * in use. This may be complicated by the use of the glue
+ * overlay.
+ *
+ * Typically there is a single syncprov mastering the entire
+ * glued tree. In that case, our contextCSN updates should
+ * go to the master DB. But if there is no syncprov on the
+ * master DB, then nothing special is needed here.
+ *
+ * Alternatively, there may be individual syncprov overlays
+ * on each glued branch. In that case, each syncprov only
+ * knows about changes within its own branch. And so our
+ * contextCSN updates should only go to the local DB.
+ */
if ( !si->si_wbe ) {
- if ( SLAP_GLUE_SUBORDINATE( be )) {
- si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
+ BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
+ if ( overlay_is_inst( top_be, "syncprov" ))
+ si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ else
+ si->si_wbe = be;
} else {
si->si_wbe = be;
}
}
+ if ( !si->si_schemachecking )
+ op->o_no_schema_check = 1;
/* Establish session, do search */
if ( !si->si_ld ) {
si->si_refreshDelete = 0;
si->si_refreshPresent = 0;
+
+ /* use main DB when retrieving contextCSN */
+ op->o_bd = si->si_wbe;
+ op->o_dn = op->o_bd->be_rootdn;
+ op->o_ndn = op->o_bd->be_rootndn;
rc = do_syncrep1( op, si );
}
if ( rc == LDAP_SUCCESS ) {
ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
+ /* use current DB */
+ op->o_bd = be;
+ op->o_dn = op->o_bd->be_rootdn;
+ op->o_ndn = op->o_bd->be_rootndn;
rc = do_syncrep2( op, si );
if ( rc == LDAP_SYNC_REFRESH_REQUIRED ) {
rc = ldap_sync_search( si, op->o_tmpmemctx );
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;
}
- if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
- /* If we succeeded, enable the connection for further listening.
- * If we failed, tear down the connection and reschedule.
- */
- if ( rc == LDAP_SUCCESS ) {
- if ( si->si_conn ) {
- connection_client_enable( si->si_conn );
- } else {
- si->si_conn = connection_client_setup( s, do_syncrepl, arg );
- }
- } else if ( si->si_conn ) {
- dostop = 1;
+ if ( rc != SYNC_PAUSED ) {
+ if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+ /* If we succeeded, enable the connection for further listening.
+ * If we failed, tear down the connection and reschedule.
+ */
+ if ( rc == LDAP_SUCCESS ) {
+ if ( si->si_conn ) {
+ connection_client_enable( si->si_conn );
+ } else {
+ si->si_conn = connection_client_setup( s, do_syncrepl, arg );
+ }
+ } else if ( si->si_conn ) {
+ dostop = 1;
+ }
+ } else {
+ if ( rc == -2 ) rc = 0;
}
- } else {
- if ( rc == -2 ) rc = 0;
}
}
- /* At this point, we have 4 cases:
+ /* At this point, we have 5 cases:
* 1) for any hard failure, give up and remove this task
- * 2) for ServerDown, reschedule this task to run
- * 3) for Refresh and Success, reschedule to run
- * 4) for Persist and Success, reschedule to defer
+ * 2) for ServerDown, reschedule this task to run later
+ * 3) for threadpool pause, reschedule to run immediately
+ * 4) for Refresh and Success, reschedule to run
+ * 5) for Persist and Success, reschedule to defer
*/
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
si->si_conn = NULL;
}
- if ( rc == LDAP_SUCCESS ) {
+ if ( rc == SYNC_PAUSED ) {
+ rtask->interval.tv_sec = 0;
+ ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
+ rtask->interval.tv_sec = si->si_interval;
+ rc = 0;
+ } else if ( rc == LDAP_SUCCESS ) {
if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
defer = 0;
}
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 );
} else {
op->orm_modlist = modlist;
op->o_bd = si->si_wbe;
- op->o_permissive_modify = SLAP_CONTROL_NONCRITICAL;
rc = op->o_bd->be_modify( op, &rs );
- op->o_permissive_modify = SLAP_CONTROL_NONE;
modlist = op->orm_modlist;
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
"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;
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 );
&nullattr
};
AttributeDescription *opattr;
- Modifications *mod, **modtail, **ml;
int i;
- for ( mod = op->orr_modlist;
- mod->sml_next;
- mod = mod->sml_next )
- ;
- modtail = &mod->sml_next;
-
- /* pull mod off incoming modlist, append to orr_modlist */
+ modtail = &m2;
+ /* pull mod off incoming modlist */
for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
- for ( ml = modlist; *ml; ml = &(*ml)->sml_next )
+ for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
{
if ( (*ml)->sml_desc == opattr ) {
mod = *ml;
}
}
}
+ /* 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;
- goto done;
+ /* 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;
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;
Operation *op,
syncinfo_t *si,
BerVarray uuids,
- struct berval *cookiecsn )
+ struct sync_cookie *sc,
+ int m )
{
Backend* be = op->o_bd;
slap_callback cb = { NULL };
}
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 );
- op->ors_filterstr = si->si_filterstr;
+ /* In multimaster, updates can continue to arrive while
+ * we're searching. Limit the search result to entries
+ * older than our newest cookie CSN.
+ */
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ Filter *f;
+ int i;
+
+ f = mmf;
+ f->f_choice = LDAP_FILTER_AND;
+ 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++ ) {
+ if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 )
+ f->f_av_value = sc->ctxcsn[i];
+ }
+ of = op->ors_filter;
+ op->ors_filter = mmf;
+ filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
+ } else {
+ cf = NULL;
+ op->ors_filterstr = si->si_filterstr;
+ }
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->ors_filter = of;
+ }
+ if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
+ if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) {
+ op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
}
- if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
+
}
op->o_nocaching = 0;
if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
- if ( cookiecsn && !BER_BVISNULL( cookiecsn ) ) {
- csn = *cookiecsn;
+ if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
+ csn = sc->ctxcsn[m];
} else {
csn = si->si_syncCookie.ctxcsn[0];
}
struct sync_cookie *syncCookie )
{
Backend *be = op->o_bd;
- Modifications mod[2];
+ 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, len;
+ int rc, i, j;
+ ber_len_t len;
slap_callback cb = { NULL };
SlapReply rs_modify = {REP_RESULT};
- mod[0].sml_op = LDAP_MOD_DELETE;
- mod[0].sml_desc = slap_schema.si_ad_contextCSN;
- mod[0].sml_type = mod[0].sml_desc->ad_cname;
- mod[0].sml_values = NULL;
- mod[0].sml_nvalues = NULL;
- mod[0].sml_numvals = 0;
- mod[0].sml_next = &mod[1];
-
- mod[1].sml_op = LDAP_MOD_ADD;
- mod[1].sml_desc = slap_schema.si_ad_contextCSN;
- mod[1].sml_type = mod[0].sml_desc->ad_cname;
- mod[1].sml_values = NULL;
- mod[1].sml_nvalues = NULL;
- mod[1].sml_numvals = 0;
- mod[1].sml_next = NULL;
+ mod.sml_op = LDAP_MOD_REPLACE;
+ mod.sml_desc = slap_schema.si_ad_contextCSN;
+ mod.sml_type = mod.sml_desc->ad_cname;
+ mod.sml_flags = SLAP_MOD_INTERNAL;
+ mod.sml_nvalues = NULL;
+ mod.sml_next = NULL;
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 );
+ for ( i=0; i<mod.sml_numvals; i++ )
+ mod.sml_values[i] = si->si_cookieState->cs_vals[i];
+ BER_BVZERO( &mod.sml_values[i] );
+
+ /* find any CSNs in the syncCookie that are newer than the cookieState */
for ( i=0; i<syncCookie->numcsns; i++ ) {
for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
if ( syncCookie->sids[i] != si->si_cookieState->cs_sids[j] )
len = si->si_cookieState->cs_vals[j].bv_len;
if ( memcmp( syncCookie->ctxcsn[i].bv_val,
si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
- ber_bvarray_add_x( &mod[0].sml_values,
- &si->si_cookieState->cs_vals[j], op->o_tmpmemctx );
- mod[0].sml_numvals++;
- ber_bvarray_add_x( &mod[1].sml_values,
- &syncCookie->ctxcsn[i], op->o_tmpmemctx );
- mod[1].sml_numvals++;
- if ( BER_BVISNULL( &first ))
+ mod.sml_values[j] = syncCookie->ctxcsn[i];
+ 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;
}
/* there was no match for this SID, it's a new CSN */
if ( j == si->si_cookieState->cs_num ) {
- ber_bvarray_add_x( &mod[1].sml_values,
- &syncCookie->ctxcsn[i], op->o_tmpmemctx );
- mod[1].sml_numvals++;
- if ( BER_BVISNULL( &first ))
+ mod.sml_values = op->o_tmprealloc( mod.sml_values,
+ ( 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] );
+ 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 ( 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;
op->o_req_ndn = op->o_bd->be_nsuffix[0];
/* update contextCSN */
- op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
-
- if ( mod[0].sml_values )
- op->orm_modlist = mod;
- else
- op->orm_modlist = &mod[1];
+ op->o_dont_replicate = 1;
+ op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
rc = op->o_bd->be_modify( op, &rs_modify );
op->orm_no_opattrs = 0;
- op->o_msgid = 0;
+ op->o_dont_replicate = 0;
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
slap_sync_cookie_free( &si->si_syncCookie, 0 );
slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
/* If we replaced any old values */
- if ( mod[0].sml_values ) {
- for ( i=0; !BER_BVISNULL( &mod[0].sml_values[i] ); i++ ) {
- for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
- if ( mod[0].sml_values[i].bv_val !=
- si->si_cookieState->cs_vals[j].bv_val )
- continue;
- ber_bvreplace( &si->si_cookieState->cs_vals[j],
- &mod[1].sml_values[i] );
- break;
- }
- }
- } else {
- /* Else we just added */
- si->si_cookieState->cs_num += syncCookie->numcsns;
- value_add( &si->si_cookieState->cs_vals, syncCookie->ctxcsn );
+ for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
+ if ( mod.sml_values[i].bv_val != si->si_cookieState->cs_vals[i].bv_val )
+ ber_bvreplace( &si->si_cookieState->cs_vals[i],
+ &mod.sml_values[i] );
+ }
+ /* Handle any added values */
+ if ( i < mod.sml_numvals ) {
+ si->si_cookieState->cs_num = mod.sml_numvals;
+ value_add( &si->si_cookieState->cs_vals, &mod.sml_values[i] );
free( si->si_cookieState->cs_sids );
si->si_cookieState->cs_sids = slap_parse_csn_sids(
si->si_cookieState->cs_vals, si->si_cookieState->cs_num, NULL );
op->o_bd = be;
op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &op->o_csn );
- if ( mod[1].sml_next ) slap_mods_free( mod[1].sml_next, 1 );
- op->o_tmpfree( mod[1].sml_values, op->o_tmpmemctx );
- op->o_tmpfree( mod[0].sml_values, 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;
}
}
}
+ /* Don't delete/add an objectClass, always use the replace op.
+ * Modify would fail if provider has replaced entry with a new,
+ * and the new explicitly includes a superior of a class that was
+ * only included implicitly in the old entry. Ref ITS#5517.
+ *
+ * Also use replace op if attr has no equality matching rule.
+ * (ITS#5781)
+ */
+ if ( nn && no < o &&
+ ( old->a_desc == slap_schema.si_ad_objectClass ||
+ !old->a_desc->ad_type->sat_equality ))
+ no = o;
+
i = j;
/* all old values were deleted, just use the replace op */
if ( no == o ) {
if ( dni->new_entry ) {
Modifications **modtail, **ml;
Attribute *old, *new;
- int is_ctx;
+ struct berval old_rdn, new_rdn;
+ struct berval old_p, new_p;
+ 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] );
/* Did the DN change?
+ * case changes in the parent are ignored,
+ * we only want to know if the RDN was
+ * actually changed.
*/
- if ( !dn_match( &rs->sr_entry->e_name,
- &dni->new_entry->e_name ) )
+ dnRdn( &rs->sr_entry->e_name, &old_rdn );
+ dnRdn( &dni->new_entry->e_name, &new_rdn );
+ dnParent( &rs->sr_entry->e_nname, &old_p );
+ dnParent( &dni->new_entry->e_nname, &new_p );
+
+ new_sup = !dn_match( &old_p, &new_p );
+ if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
{
struct berval oldRDN, oldVal;
AttributeDescription *ad = NULL;
+ int oldpos, newpos;
Attribute *a;
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 + 2;
+ oldRDN.bv_len -= oldVal.bv_len + 1;
slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
- a = attr_find( dni->new_entry->e_attrs, ad );
- if ( !a || attr_valfind( a,
+ 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,
{
dni->delOldRDN = 1;
}
- /* OK, this was just a modDN, we're done */
- return LDAP_SUCCESS;
+ /* 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, 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 );
}
if ( LogTest( LDAP_DEBUG_SYNC ) ) {
- char buf[sizeof("rid=999 not")];
+ char buf[sizeof("rid=999 non")];
snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
- present_uuid ? "got" : "not" );
+ present_uuid ? "" : "non" );
- Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s UUID %s, dn %s\n",
+ Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %spresent UUID %s, dn %s\n",
buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
}
{
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 */
- 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_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 );
}
+ 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 );
#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;
}
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:
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 ) {
init_syncrepl( si );
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
si->si_interval, do_syncrepl, si, "do_syncrepl",
si->si_ridtxt );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
if ( si->si_re )
rc = config_sync_shadow( c ) ? -1 : 0;
else
/* mirrormode still needs to see this flag in tool mode */
rc = config_sync_shadow( c ) ? -1 : 0;
}
+ ldap_free_urldesc( lud );
}
#ifdef HAVE_TLS
"Config: ** successfully added syncrepl \"%s\"\n",
BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
"(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
- if ( !si->si_schemachecking ) {
- SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
- }
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;
}
}
{
struct berval bc, uri;
char buf[BUFSIZ*2], *ptr;
+ ber_len_t len;
int i;
-
-#define WHATSLEFT ( sizeof( buf ) - ( ptr - buf ) )
+# define WHATSLEFT ((ber_len_t) (&buf[sizeof( buf )] - ptr))
BER_BVZERO( bv );
ptr = buf;
assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
- ptr += snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
+ len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
si->si_rid, si->si_bindconf.sb_uri.bv_val );
- if ( ptr - buf >= sizeof( buf ) ) return;
+ if ( len >= sizeof( buf ) ) return;
+ ptr += len;
if ( !BER_BVISNULL( &bc ) ) {
if ( WHATSLEFT <= bc.bv_len ) {
free( bc.bv_val );
if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
old = ptr;
- /* FIXME: add check for overflow */
ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
+ if ( ptr == NULL ) return;
if ( si->si_allattrs ) {
if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
if ( old != ptr ) *ptr++ = ',';
if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
- /* FIXME: add check for overflow */
ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
+ if ( ptr == NULL ) return;
}
if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
dd /= 60;
hh = dd % 24;
dd /= 24;
- ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
- ptr += snprintf( ptr, WHATSLEFT, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
- if ( ptr - buf >= sizeof( buf ) ) return;
- } else if ( si->si_retryinterval ) {
- int space=0;
+ len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
+ INTERVALSTR, dd, hh, mm, ss );
+ if ( len >= WHATSLEFT ) return;
+ ptr += len;
+ }
+
+ if ( si->si_got & GOT_RETRY ) {
+ const char *space = "";
if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
for (i=0; si->si_retryinterval[i]; i++) {
- if ( space ) *ptr++ = ' ';
- space = 1;
- ptr += snprintf( ptr, WHATSLEFT, "%ld ", (long) si->si_retryinterval[i] );
+ len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
+ (long) si->si_retryinterval[i] );
+ space = " ";
+ if ( WHATSLEFT - 1 <= len ) return;
+ ptr += len;
if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
*ptr++ = '+';
- else
- ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+ else {
+ len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+ if ( WHATSLEFT <= len ) return;
+ ptr += len;
+ }
}
if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
*ptr++ = '"';
+ } else {
+ ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
}
if ( si->si_slimit ) {
- if ( WHATSLEFT <= STRLENOF( " " SLIMITSTR "=" ) ) return;
- ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
- ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_slimit );
+ len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
+ if ( WHATSLEFT <= len ) return;
+ ptr += len;
}
if ( si->si_tlimit ) {
- if ( WHATSLEFT <= STRLENOF( " " TLIMITSTR "=" ) ) return;
- ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
- ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_tlimit );
+ len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
+ if ( WHATSLEFT <= len ) return;
+ ptr += len;
}
if ( si->si_syncdata ) {
}
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 ) {
* 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_runqueue_isrunning( &slapd_rq, si->si_re ) ) {
- si->si_ctype = 0;
+ if ( si->si_re ) {
+ 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 ( 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;
}