From 84d6a04c912aecb7c1a05445c58da19d668a9df5 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Mon, 4 Sep 2006 08:26:09 +0000 Subject: [PATCH] improve timeout support (ITS#4157, ITS#4663) --- doc/man/man5/slapd-meta.5 | 13 ++-- servers/slapd/back-meta/add.c | 2 +- servers/slapd/back-meta/back-meta.h | 4 +- servers/slapd/back-meta/bind.c | 97 +++++++++++++++++++++++++---- servers/slapd/back-meta/config.c | 36 +++++++---- servers/slapd/back-meta/delete.c | 2 +- servers/slapd/back-meta/modify.c | 2 +- servers/slapd/back-meta/modrdn.c | 2 +- 8 files changed, 122 insertions(+), 36 deletions(-) diff --git a/doc/man/man5/slapd-meta.5 b/doc/man/man5/slapd-meta.5 index 58d6760439..95a1603552 100644 --- a/doc/man/man5/slapd-meta.5 +++ b/doc/man/man5/slapd-meta.5 @@ -68,17 +68,16 @@ lastmod off .fi .RE .LP -for every +for .B ldap and .B meta -database. -This is because operational attributes related to entry creation and -modification should not be proxied, as they could be mistakenly written +databases. +This was required because operational attributes related to entry creation +and modification should not be proxied, as they could be mistakenly written to the target server(s), generating an error. -The current implementation automatically sets lastmod to off, so its use -is redundant and should be omitted, because the lastmod directive will -be deprecated in the future. +The current implementation automatically sets lastmod to \fBoff\fP, +so its use is redundant and should be omitted. .SH SPECIAL CONFIGURATION DIRECTIVES Target configuration starts with the "uri" directive. diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index 311b6d2f04..66afd66e11 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -179,7 +179,7 @@ retry:; rs->sr_err = ldap_add_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val, attrs, ctrls, NULL, &msgid ); rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid, - mt->mt_timeout[ LDAP_BACK_OP_ADD ], LDAP_BACK_SENDRESULT ); + mt->mt_timeout[ SLAP_OP_ADD ], LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index c752a7d8d6..f337ea551a 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -273,7 +273,7 @@ typedef struct metatarget_t { time_t mt_network_timeout; struct timeval mt_bind_timeout; #define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT - time_t mt_timeout[ LDAP_BACK_OP_LAST ]; + time_t mt_timeout[ SLAP_OP_LAST ]; } metatarget_t; typedef struct metadncache_t { @@ -334,7 +334,7 @@ typedef struct metainfo_t { time_t mi_conn_ttl; time_t mi_idle_timeout; struct timeval mi_bind_timeout; - time_t mi_timeout[ LDAP_BACK_OP_LAST ]; + time_t mi_timeout[ SLAP_OP_LAST ]; } metainfo_t; typedef enum meta_op_type { diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index ca85a9202c..6d2f75d739 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -319,6 +319,43 @@ meta_back_bind_op_result( op->o_log_prefix, candidate, 0 ); if ( rs->sr_err == LDAP_SUCCESS ) { + time_t stoptime = (time_t)(-1), + timeout; + int timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + const char *timeout_text = "Operation timed out"; + slap_op_t opidx = slap_req2op( op->o_tag ); + + /* since timeout is not specified, compute and use + * the one specific to the ongoing operation */ + if ( opidx == LDAP_REQ_SEARCH ) { + if ( op->ors_tlimit <= 0 ) { + timeout = 0; + + } else { + timeout = op->ors_tlimit; + timeout_err = LDAP_TIMELIMIT_EXCEEDED; + timeout_text = NULL; + } + + } else { + timeout = mt->mt_timeout[ opidx ]; + } + + /* better than nothing :) */ + if ( timeout == 0 ) { + if ( mi->mi_idle_timeout ) { + timeout = mi->mi_idle_timeout; + + } else if ( mi->mi_conn_ttl ) { + timeout = mi->mi_conn_ttl; + } + } + + if ( timeout ) { + stoptime = op->o_time + timeout; + } + LDAP_BACK_TV_SET( &tv ); /* @@ -328,11 +365,15 @@ retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: +#if 0 Debug( LDAP_DEBUG_ANY, "%s meta_back_bind_op_result[%d]: ldap_result=0 nretries=%d.\n", op->o_log_prefix, candidate, nretries ); +#endif - if ( nretries != META_RETRY_NEVER ) { + if ( nretries != META_RETRY_NEVER + || ( timeout && slap_get_time() <= stoptime ) ) + { ldap_pvt_thread_yield(); if ( nretries > 0 ) { nretries--; @@ -341,16 +382,17 @@ retry:; goto retry; } - /* FIXME: binds cannot be abandoned */ /* don't let anyone else use this handler, * because there's a pending bind that will not * be acknowledged */ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); ldap_unbind_ext( msc->msc_ld, NULL, NULL ); msc->msc_ld = NULL; - rs->sr_err = LDAP_BUSY; LDAP_BACK_CONN_BINDING_CLEAR( msc ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + + rs->sr_err = timeout_err; + rs->sr_text = timeout_text; break; case -1: @@ -876,24 +918,55 @@ meta_back_op_result( int rc; struct timeval tv; LDAPMessage *res = NULL; + time_t stoptime = (time_t)(-1); + int timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + const char *timeout_text = "Operation timed out"; - if ( timeout ) { - tv.tv_sec = timeout; - tv.tv_usec = 0; + /* if timeout is not specified, compute and use + * the one specific to the ongoing operation */ + if ( timeout == (time_t)(-1) ) { + slap_op_t opidx = slap_req2op( op->o_tag ); - } else { - LDAP_BACK_TV_SET( &tv ); + if ( opidx == SLAP_OP_SEARCH ) { + if ( op->ors_tlimit <= 0 ) { + timeout = 0; + + } else { + timeout = op->ors_tlimit; + timeout_err = LDAP_TIMELIMIT_EXCEEDED; + timeout_text = NULL; + } + + } else { + timeout = mt->mt_timeout[ opidx ]; + } } + /* better than nothing :) */ + if ( timeout == 0 ) { + if ( mi->mi_idle_timeout ) { + timeout = mi->mi_idle_timeout; + + } else if ( mi->mi_conn_ttl ) { + timeout = mi->mi_conn_ttl; + } + } + + if ( timeout ) { + stoptime = op->o_time + timeout; + } + + LDAP_BACK_TV_SET( &tv ); + retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: - if ( timeout ) { + if ( timeout && slap_get_time() > stoptime ) { (void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok ); - rs->sr_err = op->o_protocol >= LDAP_VERSION3 ? - LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; - rs->sr_text = "Operation timed out"; + rs->sr_err = timeout_err; + rs->sr_text = timeout_text; break; } diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index 3fd0b2dbed..70d6a179a8 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -186,7 +186,7 @@ meta_back_db_config( mt->mt_version = mi->mi_version; mt->mt_network_timeout = mi->mi_network_timeout; mt->mt_bind_timeout = mi->mi_bind_timeout; - for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) { + for ( c = 0; c < SLAP_OP_LAST; c++ ) { mt->mt_timeout[ c ] = mi->mi_timeout[ c ]; } @@ -890,7 +890,7 @@ meta_back_db_config( if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, - "%s: line %d: \"timeout [{add|delete|modify|modrdn}=] [...]\" takes at least 1 argument\n", + "%s: line %d: \"timeout [{add|bind|delete|modify|modrdn}=] [...]\" takes at least 1 argument\n", fname, lineno, 0 ); return( 1 ); } @@ -903,19 +903,33 @@ meta_back_db_config( if ( sep != NULL ) { size_t len = sep - argv[ c ]; - if ( strncasecmp( argv[ c ], "add", len ) == 0 ) { - t = &tv[ LDAP_BACK_OP_ADD ]; + if ( strncasecmp( argv[ c ], "bind", len ) == 0 ) { + t = &tv[ SLAP_OP_BIND ]; + /* unbind makes little sense */ + } else if ( strncasecmp( argv[ c ], "add", len ) == 0 ) { + t = &tv[ SLAP_OP_ADD ]; } else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) { - t = &tv[ LDAP_BACK_OP_DELETE ]; - } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) { - t = &tv[ LDAP_BACK_OP_MODIFY ]; + t = &tv[ SLAP_OP_DELETE ]; } else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) { - t = &tv[ LDAP_BACK_OP_MODRDN ]; + t = &tv[ SLAP_OP_MODRDN ]; + } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) { + t = &tv[ SLAP_OP_MODIFY ]; + } else if ( strncasecmp( argv[ c ], "compare", len ) == 0 ) { + t = &tv[ SLAP_OP_COMPARE ]; +#if 0 /* uses timelimit instead */ + } else if ( strncasecmp( argv[ c ], "search", len ) == 0 ) { + t = &tv[ SLAP_OP_SEARCH ]; +#endif + /* abandon makes little sense */ +#if 0 /* not implemented yet */ + } else if ( strncasecmp( argv[ c ], "extended", len ) == 0 ) { + t = &tv[ SLAP_OP_EXTENDED ]; +#endif } else { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), - "unknown operation \"%s\" for timeout #%d", - argv[ c ], c ); + "unknown/unhandled operation \"%s\" for timeout #%d", + argv[ c ], c - 1 ); Debug( LDAP_DEBUG_ANY, "%s: line %d: %s.\n", fname, lineno, buf ); @@ -940,7 +954,7 @@ meta_back_db_config( } else { int i; - for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) { + for ( i = 0; i < SLAP_OP_LAST; i++ ) { tv[ i ] = (time_t)val; } } diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index 2d7ee67454..586f4bcffe 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -77,7 +77,7 @@ retry:; rs->sr_err = ldap_delete_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val, ctrls, NULL, &msgid ); rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid, - mt->mt_timeout[ LDAP_BACK_OP_DELETE ], LDAP_BACK_SENDRESULT ); + mt->mt_timeout[ SLAP_OP_DELETE ], LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { diff --git a/servers/slapd/back-meta/modify.c b/servers/slapd/back-meta/modify.c index bde4dd220a..437d744c92 100644 --- a/servers/slapd/back-meta/modify.c +++ b/servers/slapd/back-meta/modify.c @@ -188,7 +188,7 @@ retry:; rs->sr_err = ldap_modify_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val, modv, ctrls, NULL, &msgid ); rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid, - mt->mt_timeout[ LDAP_BACK_OP_MODIFY ], LDAP_BACK_SENDRESULT ); + mt->mt_timeout[ SLAP_OP_MODIFY ], LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { diff --git a/servers/slapd/back-meta/modrdn.c b/servers/slapd/back-meta/modrdn.c index 1ec273a9bb..c009afc84c 100644 --- a/servers/slapd/back-meta/modrdn.c +++ b/servers/slapd/back-meta/modrdn.c @@ -132,7 +132,7 @@ retry:; mnewSuperior.bv_val, op->orr_deleteoldrdn, ctrls, NULL, &msgid ); rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid, - mt->mt_timeout[ LDAP_BACK_OP_MODRDN ], LDAP_BACK_SENDRESULT ); + mt->mt_timeout[ SLAP_OP_MODRDN ], LDAP_BACK_SENDRESULT ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { -- 2.39.5