backport write operation timeouts from back-meta to back-ldap; minor cleanup & silence warnings

This commit is contained in:
Pierangelo Masarati 2005-11-06 23:29:10 +00:00
parent fc2912ba92
commit 4cab386d13
19 changed files with 171 additions and 47 deletions

View File

@ -319,6 +319,21 @@ If set to
.BR discover ,
support is detected by reading the remote server's root DSE.
.TP
.B timeout [{add|delete|modify|modrdn}=]<val> [...]
This directive allows to set per-operation timeouts.
If no operation is specified, it affects all.
Currently, only write operations are addressed, because searches
can already be limited by means of the
.B limits
directive (see
.BR slapd.conf (5)
for details), and other operations are not supposed to incur into the
need for timeouts.
Note: if the timelimit is exceeded, the operation is abandoned;
the protocol does not provide any means to rollback the operation,
so the client will not know if the operation eventually succeeded or not.
.SH BACKWARD COMPATIBILITY
The LDAP backend has been heavily reworked between releases 2.2 and 2.3;
as a side-effect, some of the traditional directives have been

View File

@ -36,6 +36,8 @@ ldap_back_add(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
int i = 0,
j = 0;
@ -100,7 +102,8 @@ ldap_back_add(
retry:
rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
ctrls, NULL, &msgid );
rs->sr_err = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rs->sr_err = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_ADD ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {

View File

@ -93,6 +93,17 @@ enum {
LDAP_BACK_IDASSERT_OTHERID
};
/*
* operation enumeration for timeouts
*/
enum {
LDAP_BACK_OP_ADD = 0,
LDAP_BACK_OP_DELETE,
LDAP_BACK_OP_MODIFY,
LDAP_BACK_OP_MODRDN,
LDAP_BACK_OP_LAST
};
struct ldapinfo {
char *url;
LDAPURLDesc *lud;
@ -166,6 +177,8 @@ struct ldapinfo {
/* FIXME: automatic rwm instantiation removed */
int rwm_started;
#endif
time_t timeout[ LDAP_BACK_OP_LAST ];
};
typedef enum ldap_back_send_t {

View File

@ -71,7 +71,7 @@ ldap_back_bind( Operation *op, SlapReply *rs )
rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
LDAP_SASL_SIMPLE,
&op->orb_cred, op->o_ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
if ( rc == LDAP_SUCCESS ) {
/* If defined, proxyAuthz will be used also when
@ -737,7 +737,7 @@ retry:;
return 0;
}
rc = ldap_back_op_result( lc, op, rs, msgid, sendok );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
@ -800,6 +800,7 @@ ldap_back_op_result(
Operation *op,
SlapReply *rs,
ber_int_t msgid,
time_t timeout,
ldap_back_send_t sendok )
{
char *match = NULL;
@ -818,12 +819,26 @@ ldap_back_op_result(
int rc;
struct timeval tv;
LDAP_BACK_TV_SET( &tv );
if ( timeout ) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
} else {
LDAP_BACK_TV_SET( &tv );
}
retry:;
/* if result parsing fails, note the failure reason */
switch ( ldap_result( lc->lc_ld, msgid, 1, &tv, &res ) ) {
rc = ldap_result( lc->lc_ld, msgid, 1, &tv, &res );
switch ( rc ) {
case 0:
if ( timeout ) {
(void)ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
rs->sr_text = "Operation timed out";
break;
}
LDAP_BACK_TV_SET( &tv );
ldap_pvt_thread_yield();
goto retry;
@ -893,6 +908,12 @@ ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_se
ldap_pvt_thread_mutex_lock( &li->conn_mutex );
if ( lc->lc_refcnt == 1 ) {
Debug( LDAP_DEBUG_ANY,
"%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
op->o_log_prefix, li->url,
BER_BVISNULL( &lc->lc_bound_ndn ) ?
"" : lc->lc_bound_ndn.bv_val );
ldap_unbind_ext( lc->lc_ld, NULL, NULL );
lc->lc_ld = NULL;
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
@ -1089,7 +1110,7 @@ ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs )
goto done;
}
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
}

View File

@ -60,7 +60,7 @@ retry:
op->orc_ava->aa_desc->ad_cname.bv_val,
&op->orc_ava->aa_value,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDRESULT );
if ( rc == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {

View File

@ -59,6 +59,7 @@ enum {
LDAP_BACK_CFG_CHASE,
LDAP_BACK_CFG_T_F,
LDAP_BACK_CFG_WHOAMI,
LDAP_BACK_CFG_TIMEOUT,
LDAP_BACK_CFG_REWRITE
};
@ -203,6 +204,14 @@ static ConfigTable ldapcfg[] = {
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "timeout", "timeout", 0, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT,
ldap_back_cf_gen, "( OLcfgDbAt:3.14 "
"NAME 'olcDbTimeout' "
"DESC 'Per-operation timeouts' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "suffixmassage", "[virtual]> <real", 2, 3, 0,
ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
ldap_back_cf_gen, NULL, NULL, NULL },
@ -235,6 +244,7 @@ static ConfigOCs ldapocs[] = {
"$ olcDbChaseReferrals "
"$ olcDbTFSupport "
"$ olcDbProxyWhoAmI "
"$ olcDbTimeout "
") )",
Cft_Database, ldapcfg},
{ NULL, 0, NULL }
@ -272,6 +282,14 @@ static slap_verbmasks t_f_mode[] = {
{ BER_BVNULL, 0 }
};
static slap_cf_aux_table timeout_table[] = {
{ BER_BVC("add="), 0 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVC("delete="), 1 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVC("modify="), 2 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVC("modrdn="), 3 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVNULL, 0, 0, 0, NULL }
};
static int
ldap_back_cf_gen( ConfigArgs *c )
{
@ -512,6 +530,25 @@ ldap_back_cf_gen( ConfigArgs *c )
}
break;
case LDAP_BACK_CFG_TIMEOUT:
BER_BVZERO( &bv );
slap_cf_aux_table_unparse( li->timeout, &bv, timeout_table );
if ( !BER_BVISNULL( &bv ) ) {
for ( i = 0; isspace( bv.bv_val[ i ] ); i++ )
/* count spaces */ ;
if ( i ) {
bv.bv_len -= i;
AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
bv.bv_len + 1 );
}
ber_bvarray_add( &c->rvalue_vals, &bv );
}
break;
default:
/* FIXME: we need to handle all... */
assert( 0 );
@ -582,6 +619,12 @@ ldap_back_cf_gen( ConfigArgs *c )
rc = 1;
break;
case LDAP_BACK_CFG_TIMEOUT:
for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
li->timeout[ i ] = 0;
}
break;
default:
/* FIXME: we need to handle all... */
assert( 0 );
@ -1040,8 +1083,7 @@ ldap_back_cf_gen( ConfigArgs *c )
} else {
li->flags &= ~LDAP_BACK_F_SAVECRED;
}
break;
}
} break;
case LDAP_BACK_CFG_CHASE: {
int dochase = 0;
@ -1066,8 +1108,7 @@ ldap_back_cf_gen( ConfigArgs *c )
} else {
li->flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
}
break;
}
} break;
case LDAP_BACK_CFG_T_F:
i = verb_to_mask( c->argv[1], t_f_mode );
@ -1104,8 +1145,36 @@ ldap_back_cf_gen( ConfigArgs *c )
} else {
li->flags &= ~LDAP_BACK_F_PROXY_WHOAMI;
}
} break;
case LDAP_BACK_CFG_TIMEOUT:
if ( c->argc < 2 ) {
return 1;
}
for ( i = 1; i < c->argc; i++ ) {
if ( isdigit( c->argv[ i ][ 0 ] ) ) {
char *next;
int j;
unsigned u;
u = strtoul( c->argv[ i ], &next, 0 );
if ( next == c->argv[ i ] || next[ 0 ] != '\0' ) {
return 1;
}
for ( j = 0; j < LDAP_BACK_OP_LAST; j++ ) {
li->timeout[ j ] = u;
}
continue;
}
if ( slap_cf_aux_table_parse( c->argv[ i ], li->timeout, timeout_table, "slapd-ldap timeout" ) ) {
return 1;
}
}
break;
}
case LDAP_BACK_CFG_REWRITE:
fprintf( stderr, "%s: line %d: "

View File

@ -36,6 +36,8 @@ ldap_back_delete(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
@ -59,7 +61,8 @@ ldap_back_delete(
retry:
rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_ndn.bv_val,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_DELETE], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {

View File

@ -36,6 +36,8 @@ ldap_back_modify(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
LDAPMod **modv = NULL,
*mods = NULL;
@ -107,7 +109,8 @@ ldap_back_modify(
retry:
rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_ndn.bv_val, modv,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_MODIFY], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {

View File

@ -36,6 +36,8 @@ ldap_back_modrdn(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
@ -67,7 +69,8 @@ retry:
rs->sr_err = ldap_rename( lc->lc_ld, op->o_req_ndn.bv_val,
op->orr_newrdn.bv_val, newSup,
op->orr_deleteoldrdn, ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_MODRDN ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {

View File

@ -55,7 +55,7 @@ int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_bac
int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok);
int ldap_back_map_result(SlapReply *rs);
int ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs,
ber_int_t msgid, ldap_back_send_t sendok);
ber_int_t msgid, time_t timeout, ldap_back_send_t sendok);
int back_ldap_LTX_init_module(int argc, char *argv[]);
int ldap_back_init_cf( BackendInfo *bi );

View File

@ -143,7 +143,7 @@ ldap_back_search(
{
struct ldapconn *lc;
struct timeval tv;
time_t stoptime;
time_t stoptime = (time_t)-1;
LDAPMessage *res,
*e;
int rc = 0,
@ -223,7 +223,7 @@ fail:;
goto retry;
}
}
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
ldap_back_freeconn( op, lc );
lc = NULL;
goto finish;
@ -346,7 +346,7 @@ fail:;
/* cleanup */
if ( references ) {
ldap_value_free( references );
ber_memvfree( (void **)references );
ch_free( rs->sr_ref );
rs->sr_ref = NULL;
}
@ -404,7 +404,7 @@ fail:;
/* cleanup */
if ( references ) {
ldap_value_free( references );
ber_memvfree( (void **)references );
}
rc = 0;

View File

@ -178,8 +178,8 @@ retry:;
LDAPMessage *res = NULL;
int rc;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_ADD ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_ADD ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_ADD ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_ADD ];
tv.tv_usec = 0;
tvp = &tv;
}

View File

@ -205,14 +205,6 @@ typedef struct metaconn_t {
* in one block with the metaconn_t structure */
} metaconn_t;
enum {
META_OP_ADD = 0,
META_OP_DELETE,
META_OP_MODIFY,
META_OP_MODRDN,
META_OP_LAST
};
typedef struct metatarget_t {
char *mt_uri;
int mt_scope;
@ -236,7 +228,7 @@ typedef struct metatarget_t {
unsigned mt_flags;
int mt_version;
time_t mt_timeout[ META_OP_LAST ];
time_t mt_timeout[ LDAP_BACK_OP_LAST ];
} metatarget_t;
typedef struct metadncache_t {
@ -279,7 +271,7 @@ typedef struct metainfo_t {
#define META_BACK_DEFER_ROOTDN_BIND(mi) ( (mi)->flags & META_BACK_F_DEFER_ROOTDN_BIND )
int mi_version;
time_t mi_timeout[ META_OP_LAST ];
time_t mi_timeout[ LDAP_BACK_OP_LAST ];
} metainfo_t;
typedef enum meta_op_type {

View File

@ -163,7 +163,7 @@ meta_back_db_config(
mi->mi_targets[ i ].mt_flags = mi->flags;
mi->mi_targets[ i ].mt_version = mi->mi_version;
for ( c = 0; c < META_OP_LAST; c++ ) {
for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) {
mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ];
}
@ -619,13 +619,13 @@ meta_back_db_config(
size_t len = sep - argv[ c ];
if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
t = &tv[ META_OP_ADD ];
t = &tv[ LDAP_BACK_OP_ADD ];
} else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) {
t = &tv[ META_OP_DELETE ];
t = &tv[ LDAP_BACK_OP_DELETE ];
} else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
t = &tv[ META_OP_MODIFY ];
t = &tv[ LDAP_BACK_OP_MODIFY ];
} else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) {
t = &tv[ META_OP_MODRDN ];
t = &tv[ LDAP_BACK_OP_MODRDN ];
} else {
fprintf( stderr,
"%s: line %d: unknown operation \"%s\" for timeout #%d.\n",
@ -652,7 +652,7 @@ meta_back_db_config(
} else {
int i;
for ( i = 0; i < META_OP_LAST; i++ ) {
for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
tv[ i ] = val;
}
}

View File

@ -448,9 +448,11 @@ retry_lock:;
goto retry_lock;
}
Debug( LDAP_DEBUG_ANY, "%s meta_back_retry: retrying uri=\"%s\" DN=\"%s\"\n",
Debug( LDAP_DEBUG_ANY,
"%s meta_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
op->o_log_prefix, mt->mt_uri,
BER_BVISNULL( &msc->msc_bound_ndn ) ? "" : msc->msc_bound_ndn.bv_val );
BER_BVISNULL( &msc->msc_bound_ndn ) ?
"" : msc->msc_bound_ndn.bv_val );
meta_clear_one_candidate( msc );
LDAP_BACK_CONN_ISBOUND_CLEAR( msc );

View File

@ -76,8 +76,8 @@ retry:;
LDAPMessage *res = NULL;
int rc;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_DELETE ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_DELETE ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_DELETE ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_DELETE ];
tv.tv_usec = 0;
tvp = &tv;
}

View File

@ -186,8 +186,8 @@ retry:;
struct timeval tv, *tvp = NULL;
LDAPMessage *res = NULL;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODIFY ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODIFY ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODIFY ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODIFY ];
tv.tv_usec = 0;
tvp = &tv;
}

View File

@ -117,8 +117,8 @@ retry:;
LDAPMessage *res = NULL;
int rc;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODRDN ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODRDN ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODRDN ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODRDN ];
tv.tv_usec = 0;
tvp = &tv;
}

View File

@ -245,7 +245,7 @@ meta_back_search( Operation *op, SlapReply *rs )
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metaconn_t *mc;
struct timeval tv = { 0, 0 };
time_t stoptime;
time_t stoptime = (time_t)-1;
LDAPMessage *res = NULL, *e;
int rc = 0, sres = LDAP_SUCCESS;
char *matched = NULL;