selection in case multiple targets would result from an uncached
search; forever means cache never expires; disabled means no DN
caching; otherwise a valid ( > 0 ) ttl in seconds is required.
+.TP
+.B nretries {forever|never|<nretries>}
+This directive defines how many times a bind should be retried
+in case of temporary failure in contacting a target. If defined
+before any target specification, it applies to all targets (by default,
+.BR never );
+the global value can be overridden by redefinitions inside each target
+specification.
.SH TARGET SPECIFICATION
Target specification starts with a "uri" directive:
.TP
#endif
} dncookie;
-#define META_BIND_NRETRIES 3
+/* TODO: allow to define it on a per-target basis */
#define META_BIND_TIMEOUT 10000
int ldap_back_dn_massage(dncookie *dc, struct berval *dn,
struct berval mt_pseudorootdn;
struct berval mt_pseudorootpw;
+ int mt_nretries;
+#define META_RETRY_UNDEFINED (-2)
+#define META_RETRY_FOREVER (-1)
+#define META_RETRY_NEVER (0)
+
struct ldaprwmap mt_rwmap;
} metatarget_t;
int mi_defaulttarget;
int mi_network_timeout;
#define META_DEFAULT_TARGET_NONE (-1)
+ int mi_nretries;
+
metatarget_t **mi_targets;
SlapReply *mi_candidates;
op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_SUCCESS ) {
LDAPMessage *res;
- struct timeval tv = { 0, 0 };
+ struct timeval tv;
int rc;
- int nretries = META_BIND_NRETRIES;
+ int nretries = mt->mt_nretries;
/*
* handle response!!!
*/
retry:;
+ tv.tv_sec = 0;
+ tv.tv_usec = META_BIND_TIMEOUT;
switch ( ldap_result( msc->msc_ld, msgid, 0, &tv, &res ) ) {
case 0:
- if ( nretries > 0 ) {
+ Debug( LDAP_DEBUG_ANY, "%s meta_back_single_bind: ldap_result=%d nretries=%d\n",
+ op->o_log_prefix, 0, nretries );
+
+ if ( nretries != META_RETRY_NEVER ) {
ldap_pvt_thread_yield();
- tv.tv_sec = 0;
- tv.tv_usec = META_BIND_TIMEOUT;
- nretries--;
+ if ( nretries > 0 ) {
+ nretries--;
+ }
goto retry;
}
rs->sr_err = LDAP_BUSY;
ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
&rs->sr_err );
- Debug( LDAP_DEBUG_ANY, "### %s meta_back_single_bind(%s) err=%d\n",
- op->o_log_prefix, mdn.bv_val, rs->sr_err );
+ Debug( LDAP_DEBUG_ANY, "### %s meta_back_single_bind: err=%d nretries=%d\n",
+ op->o_log_prefix, rs->sr_err, nretries );
- if ( rs->sr_err == LDAP_UNAVAILABLE && nretries > 0 ) {
+ rc = slap_map_api2result( rs );
+ if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL;
msc->msc_bound = 0;
rc = meta_back_init_one_conn( op, rs, mt, msc,
LDAP_BACK_DONTSEND );
if ( rc ) {
- nretries--;
+ if ( nretries > 0 ) {
+ nretries--;
+ }
ldap_pvt_thread_yield();
goto rebind;
}
metaconn_t *mc,
int candidate,
ldap_back_send_t sendok,
- int retries )
+ int nretries )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metatarget_t *mt = mi->mi_targets[ candidate ];
NULL, NULL, &msgid );
if ( rc == LDAP_SUCCESS ) {
LDAPMessage *res;
- struct timeval tv = { 0, 0 };
+ struct timeval tv;
/*
* handle response!!!
tv.tv_usec = META_BIND_TIMEOUT;
switch ( ldap_result( msc->msc_ld, msgid, 0, &tv, &res ) ) {
case 0:
- if ( retries > 0 ) {
+ Debug( LDAP_DEBUG_ANY, "%s meta_back_single_dobind: ldap_result=%d nretries=%d\n",
+ op->o_log_prefix, 0, nretries );
+
+ if ( nretries != META_RETRY_NEVER ) {
ldap_pvt_thread_yield();
- retries--;
+ if ( nretries > 0 ) {
+ nretries--;
+ }
goto retry;
}
ldap_get_option( msc->msc_ld,
LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
- Debug( LDAP_DEBUG_ANY, "### %s meta_back_single_dobind(\"\") err=%d\n",
- op->o_log_prefix, rs->sr_err, 0 );
+ Debug( LDAP_DEBUG_ANY, "### %s meta_back_single_dobind: err=%d nretries=%d\n",
+ op->o_log_prefix, rs->sr_err, nretries );
rc = slap_map_api2result( rs );
- if ( rc == LDAP_UNAVAILABLE && retries > 0 ) {
+ if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
msc->msc_ld = NULL;
msc->msc_bound = 0;
/* mc here must be the regular mc, reset and ready for init */
rc = meta_back_init_one_conn( op, rs, mt, msc, LDAP_BACK_DONTSEND );
- if ( rc ) {
+ if ( rc == LDAP_SUCCESS ) {
ldap_pvt_thread_yield();
- retries--;
+ if ( nretries > 0 ) {
+ nretries--;
+ }
goto rebind;
}
}
}
}
+ rs->sr_err = rc;
if ( rc != LDAP_SUCCESS && ( sendok & LDAP_BACK_SENDERR ) ) {
- rs->sr_err = rc;
send_ldap_result( op, rs );
}
metaconn_t *mc,
ldap_back_send_t sendok )
{
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+
metasingleconn_t *msc;
int bound = 0, i;
}
for ( i = 0, msc = &mc->mc_conns[ 0 ]; !META_LAST( msc ); ++i, ++msc ) {
+ metatarget_t *mt = mi->mi_targets[ i ];
int rc;
/*
}
rc = meta_back_single_dobind( op, rs, mc, i,
- LDAP_BACK_DONTSEND, META_BIND_NRETRIES );
+ LDAP_BACK_DONTSEND, mt->mt_nretries );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "%s meta_back_dobind[%d]: "
"(anonymous) err=%d\n",
ldap_back_map_init( &mt->mt_rwmap.rwm_at, &mapping );
+ mt->mt_nretries = META_RETRY_UNDEFINED;
+
return mt;
}
return 1;
}
+ mi->mi_targets[ i ]->mt_nretries = mi->mi_nretries;
+
/*
* uri MUST be legal!
*/
return ldap_back_map_config( &mi->mi_targets[ i ]->mt_rwmap.rwm_oc,
&mi->mi_targets[ i ]->mt_rwmap.rwm_at,
fname, lineno, argc, argv );
+
+ } else if ( strcasecmp( argv[ 0 ], "nretries" ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+ int nretries = META_RETRY_UNDEFINED;
+
+ if ( argc != 2 ) {
+ fprintf( stderr,
+ "%s: line %d: need value in \"nretries <value>\"\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
+ nretries = META_RETRY_FOREVER;
+
+ } else if ( strcasecmp( argv[ 1 ], "never" ) == 0 ) {
+ nretries = META_RETRY_NEVER;
+
+ } else {
+ char *next;
+
+ nretries = strtol( argv[ 1 ], &next, 10 );
+ if ( next == argv[ 1 ] || next[ 0 ] != '\0' ) {
+ fprintf( stderr,
+ "%s: line %d: unable to parse value \"%s\" in \"nretries <value>\"\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+ }
+
+ if ( i < 0 ) {
+ mi->mi_nretries = nretries;
+
+ } else {
+ mi->mi_targets[ i ]->mt_nretries = nretries;
+ }
+
/* anything else */
} else {
return SLAP_CONF_UNKNOWN;
rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid );
if ( rs->sr_err == LDAP_SUCCESS ) {
LDAPMessage *res = NULL;
- int rc, retries = 1;
+ int rc, nretries = mt->mt_nretries;
struct timeval tv = { 0, 0 };
retry:;
rs->sr_err = LDAP_OTHER;
} else if ( rc == 0 ) {
- if ( retries ) {
- retries--;
+ if ( nretries != 0 ) {
+ if ( nretries > 0 ) {
+ nretries--;
+ }
tv.tv_sec = 0;
tv.tv_usec = 100000;
goto retry;
rc = meta_back_init_one_conn( op, rs, mt, msc, sendok );
if ( rc == LDAP_SUCCESS ) {
- rc = meta_back_single_dobind( op, rs, mc, candidate, sendok,
- META_BIND_NRETRIES );
+ rc = meta_back_single_dobind( op, rs, mc, candidate,
+ sendok, mt->mt_nretries );
}
ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
*/
} else {
+ int ncandidates = 0;
+
/* Looks like we didn't get a bind. Open a new session... */
if ( !mc ) {
mc = metaconn_alloc( mi->mi_ntargets );
&mc->mc_conns[ i ], sendok );
if ( lerr == LDAP_SUCCESS ) {
candidates[ i ].sr_tag = META_CANDIDATE;
+ ncandidates++;
} else {
* be init'd, should the other ones
* be tried?
*/
+ if ( new_conn ) {
+ ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
+ }
candidates[ i ].sr_tag = META_NOT_CANDIDATE;
err = lerr;
}
} else {
+ if ( new_conn ) {
+ ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
+ }
candidates[ i ].sr_tag = META_NOT_CANDIDATE;
}
}
+
+ if ( ncandidates == 0 ) {
+ if ( new_conn ) {
+ meta_back_conn_free( mc );
+ }
+
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ rs->sr_text = "Unable to select valid candidates";
+
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+
+ return NULL;
+ }
}
done:;
suffix "o=Example,c=US"
rootdn "cn=Manager,o=Example,c=US"
rootpw secret
+nretries forever
# local
uri "@URI2@ou=Meta,o=Example,c=US"
. $LDIFFILTER < $METACONCURRENCYOUT > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
-
+
if test $? != 0 ; then
echo "comparison failed - meta search/modification didn't succeed"
exit 1