ITS#10363 - Implement a target connection time-to-live in asyncmeta

This commit is contained in:
Nadezhda Ivanova 2025-06-24 18:10:30 +03:00 committed by Quanah Gibson-Mount
parent d1848e54ae
commit add3df9da4
14 changed files with 776 additions and 24 deletions

View file

@ -268,6 +268,47 @@ irrespective of the client's request. See
.B slapd\-meta(5)
for details.
.TP
.B conn\-ttl <time> [<interval>]
This directive causes a persistent connection to be dropped after
it has been established for the specified
.I time,
no more often that one connection per
.I interval
per target. The connection will be re-created the next time it is selected for use.
If there are pending requests in its queue, the connection will be
marked as closing and no new requests will be proxied through it.
It will be dropped after the last request one has either received a result or has timed out.
To avoid too many connections being dropped at the same time, the \fBinterval\fP
directive is introduced, to specify the minimum time interval between resetting a connection
to the same target.
The default value is 1 second. If
.I time
is set to 0, the oldest connection will be chosen for reset at every interval period. If
.I interval
is set to 0, all connections exceeding their ttl will be dropped as soon as there are no more
pending operations.
[<d>d][<h>h][<m>m][<s>[s]]
where <d>, <h>, <m> and <s> are respectively treated as days, hours,
minutes and seconds.
.B EXAMPLES
.B conn\-ttl 60s 5s
- Connections older that 60 seconds will be reset, no more often that one connection per
target every 5 seconds.
.B conn\-ttl 0 5s
- Every 5 seconds, the oldest connection of each target will be reset.
.B conn\-ttl 1h
- Connection older than 1h will be reset, no more often than once a second per target.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive. It is disabled by default.
.TP
.B default\-target [<target>]
The "default\-target" directive can also be used during target specification.
@ -331,7 +372,7 @@ for details.
.TP
.B idle\-timeout <time>
This directive causes a a persistent connection to be dropped after
This directive causes a persistent connection to be dropped after
it has been idle for the specified time. The connection will be re-created
the next time it is selected for use. A connection is considered idle if no
attempts have been made by the backend to use it to send a request to

View file

@ -63,7 +63,11 @@ LDAP_BEGIN_DECL
#define META_BACK_FCONN_INITED (0x00100000U)
#define META_BACK_FCONN_CREATING (0x00200000U)
/* connection is invalid, do not read or send, close as soon as possible */
#define META_BACK_FCONN_INVALID (0x00400000U)
/* connection is closing, do not send, but keep open for reading, reset
when no more data is expected */
#define META_BACK_FCONN_CLOSING (0x00800000U)
#define META_BACK_CONN_INITED(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED)
#define META_BACK_CONN_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED)
@ -76,6 +80,10 @@ LDAP_BEGIN_DECL
#define META_BACK_CONN_INVALID(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INVALID)
#define META_BACK_CONN_INVALID_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INVALID)
#define META_BACK_CONN_INVALID_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INVALID)
#define META_BACK_CONN_CLOSING(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_CLOSING)
#define META_BACK_CONN_CLOSING_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CLOSING)
#define META_BACK_CONN_CLOSING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CLOSING)
struct a_metainfo_t;
struct a_metaconn_t;
@ -129,14 +137,17 @@ typedef struct a_metasingleconn_t {
time_t msc_time;
time_t msc_binding_time;
time_t msc_result_time;
time_t msc_reset_time;
time_t msc_established_time;
struct berval msc_bound_ndn;
struct berval msc_cred;
unsigned msc_mscflags;
int msc_pending_ops;
/* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros
* defined for back-ldap */
#define lc_lcflags msc_mscflags
volatile int msc_active;
struct a_metaconn_t *mc;
/* Connection for the select */
Connection *conn;
} a_metasingleconn_t;
@ -240,6 +251,8 @@ typedef struct a_metacommon_t {
slap_retry_info_t mc_quarantine;
time_t mc_network_timeout;
struct timeval mc_bind_timeout;
time_t mc_conn_ttl;
time_t mc_conn_reset_interval;
#define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT
time_t mc_timeout[ SLAP_OP_LAST ];
} a_metacommon_t;
@ -299,6 +312,8 @@ typedef struct a_metatarget_t {
#define mt_bind_timeout mt_mc.mc_bind_timeout
#define mt_timeout mt_mc.mc_timeout
#define mt_quarantine mt_mc.mc_quarantine
#define mt_conn_ttl mt_mc.mc_conn_ttl
#define mt_conn_reset_interval mt_mc.mc_conn_reset_interval
#define META_BACK_TGT_ISSET(mt,f) ( ( (mt)->mt_flags & (f) ) == (f) )
#define META_BACK_TGT_ISMASK(mt,m,f) ( ( (mt)->mt_flags & (m) ) == (f) )
@ -337,6 +352,8 @@ typedef struct a_metatarget_t {
#define META_BACK_CFG_MAX_TIMEOUT_LOOP 0x70000
slap_mask_t mt_rep_flags;
int mt_timeout_ops;
/* last time a connection for this target was reset */
time_t msc_reset_time;
} a_metatarget_t;
typedef struct a_metadncache_t {
@ -382,7 +399,8 @@ typedef struct a_metainfo_t {
#define mi_bind_timeout mi_mc.mc_bind_timeout
#define mi_timeout mi_mc.mc_timeout
#define mi_quarantine mi_mc.mc_quarantine
#define mi_conn_ttl mi_mc.mc_conn_ttl
#define mi_conn_reset_interval mi_mc.mc_conn_reset_interval
a_metatarget_t **mi_targets;
a_metacandidates_t *mi_candidates;

View file

@ -68,6 +68,7 @@ enum {
LDAP_BACK_CFG_CANCEL,
LDAP_BACK_CFG_CHASE,
LDAP_BACK_CFG_CLIENT_PR,
LDAP_BACK_CFG_CONN_TTL,
LDAP_BACK_CFG_DEFAULT_T,
LDAP_BACK_CFG_NETWORK_TIMEOUT,
LDAP_BACK_CFG_NOREFS,
@ -171,6 +172,15 @@ static ConfigTable a_metacfg[] = {
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "conn-ttl", "ttl", 2, 3, 0,
ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL,
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.16 "
"NAME 'olcDbConnTtl' "
"DESC 'connection ttl' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "network-timeout", "timeout", 2, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.17 "
@ -412,7 +422,8 @@ static ConfigTable a_metacfg[] = {
"$ olcDbRebindAsUser " \
ST_ATTR \
"$ olcDbStartTLS " \
"$ olcDbTFSupport "
"$ olcDbTFSupport " \
"$ olcDbConnTtl "
static ConfigOCs a_metaocs[] = {
{ "( OLcfgDbOc:3.4 "
@ -518,6 +529,7 @@ asyncmeta_back_new_target(
a_metaconn_t *mc = &mi->mi_conns[i];
mc->mc_conns = ch_realloc( mc->mc_conns, sizeof( a_metasingleconn_t ) * mi->mi_ntargets);
memset( &(mc->mc_conns[mi->mi_ntargets-1]), 0, sizeof( a_metasingleconn_t ) );
mc->mc_conns[mi->mi_ntargets-1].mc = mc;
}
/* If this is the first target, start the timeout loop */
if ( mi->mi_ntargets == 1 ) {
@ -1149,7 +1161,22 @@ asyncmeta_back_cf_gen( ConfigArgs *c )
value_add_one( &c->rvalue_vals, &bv );
break;
#endif /* SLAPD_META_CLIENT_PR */
case LDAP_BACK_CFG_CONN_TTL:
if ( mc->mc_conn_ttl == 0 && mc->mc_conn_reset_interval == 0) {
return 1;
} else {
char buf[ SLAP_TEXT_BUFLEN ];
char *p = buf;
lutil_unparse_time( p, sizeof( p ), mc->mc_conn_ttl );
if (mc->mc_conn_reset_interval != 0) {
p += strlen( buf );
*p = ' ';
lutil_unparse_time( p, sizeof( p ), mc->mc_conn_reset_interval );
}
ber_str2bv( buf, 0, 0, &bv );
value_add_one( &c->rvalue_vals, &bv );
}
break;
case LDAP_BACK_CFG_DEFAULT_T:
if ( mt || mi->mi_defaulttarget == META_DEFAULT_TARGET_NONE )
return 1;
@ -1598,7 +1625,10 @@ asyncmeta_back_cf_gen( ConfigArgs *c )
mc->mc_ps = META_CLIENT_PR_DISABLE;
break;
#endif /* SLAPD_META_CLIENT_PR */
case LDAP_BACK_CFG_CONN_TTL:
mc->mc_conn_ttl = 0;
mc->mc_conn_reset_interval = 0;
break;
case LDAP_BACK_CFG_DEFAULT_T:
mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
break;
@ -2390,7 +2420,28 @@ asyncmeta_back_cf_gen( ConfigArgs *c )
}
}
break;
case LDAP_BACK_CFG_CONN_TTL: {
unsigned long t;
if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"unable to parse conn ttl \"%s\"",
c->argv[ 1 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
return 1;
}
mc->mc_conn_ttl = (time_t)t;
if ( ( c->argv[ 2 ] != NULL ) && lutil_parse_time( c->argv[ 2 ], &t ) ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"unable to parse conn ttl reset interval \"%s\"",
c->argv[ 2 ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
return 1;
}
mc->mc_conn_reset_interval = (time_t)t;
} break;
case LDAP_BACK_CFG_IDASSERT_BIND:
/* idassert-bind */
rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );

View file

@ -43,7 +43,7 @@ asyncmeta_conn_alloc(
{
a_metaconn_t *mc;
int ntargets = mi->mi_ntargets;
int j;
assert( ntargets > 0 );
/* malloc all in one */
@ -56,6 +56,10 @@ asyncmeta_conn_alloc(
ldap_pvt_thread_mutex_init( &mc->mc_om_mutex);
mc->mc_authz_target = META_BOUND_NONE;
mc->mc_conns = (a_metasingleconn_t *)(mc+1);
for (j = 0; j < mi->mi_ntargets; j++) {
mc->mc_conns[j].mc = mc;
}
return mc;
}
@ -120,13 +124,17 @@ asyncmeta_init_one_conn(
return rs->sr_err;
}
}
msc = &mc->mc_conns[candidate];
/*
* Already init'ed
*/
if ( LDAP_BACK_CONN_ISBOUND( msc )
|| LDAP_BACK_CONN_ISANON( msc ) )
{
msc = &mc->mc_conns[candidate];
if ( META_BACK_CONN_CLOSING( msc ) ) {
rs->sr_err = -1;
return rs->sr_err;
} else if ( LDAP_BACK_CONN_ISBOUND( msc )
|| LDAP_BACK_CONN_ISANON( msc ) ) {
/*
* Already init'ed
*/
assert( msc->msc_ld != NULL );
rs->sr_err = LDAP_SUCCESS;
return rs->sr_err;
@ -176,6 +184,8 @@ asyncmeta_init_one_conn(
goto error_return;
}
msc->msc_established_time = slap_get_time();
/*
* Set LDAP version. This will always succeed: If the client
* bound with a particular version, then so can we.
@ -506,7 +516,8 @@ asyncmeta_getconn(
i = META_TARGET_NONE,
err = LDAP_SUCCESS,
new_conn = 0,
ncandidates = 0;
ncandidates = 0,
num_conns = mi->mi_num_conns;
meta_op_type op_type = META_OP_REQUIRE_SINGLE;
@ -518,6 +529,11 @@ asyncmeta_getconn(
struct berval ndn = op->o_req_ndn,
pndn;
choose_again:
/* in case we are sent here because the connection is set to closing */
if ( mc != NULL && alloc_new > 0 ) {
asyncmeta_back_conn_free( mc );
}
if (alloc_new > 0) {
mc = asyncmeta_conn_alloc(mi);
new_conn = 0;
@ -613,6 +629,19 @@ asyncmeta_getconn(
candidates[ i ].sr_err = asyncmeta_init_one_conn( op,
rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ),
!new_conn );
if ( candidates[ i ].sr_err == -1 ) {
if ( num_conns -1 > 0 ) {
num_conns--;
ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
goto choose_again;
} else {
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Unable to find a valid connection";
ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
return NULL;
}
}
if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
if ( new_conn ) {
LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] );
@ -714,6 +743,18 @@ asyncmeta_getconn(
*/
err = asyncmeta_init_one_conn( op, rs, mc, i,
LDAP_BACK_CONN_ISPRIV( &mc_curr ), !new_conn );
if ( err == -1 ) {
if ( num_conns-1 > 0 ) {
num_conns--;
ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
goto choose_again;
} else {
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Unable to find a valid connection";
ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
return NULL;
}
}
if ( err != LDAP_SUCCESS ) {
/*
* FIXME: in case one target cannot
@ -764,6 +805,19 @@ asyncmeta_getconn(
int lerr = asyncmeta_init_one_conn( op, rs, mc, i,
LDAP_BACK_CONN_ISPRIV( &mc_curr ),
!new_conn );
/* the chosen connection is closing */
if ( lerr == -1 ) {
if ( num_conns-1 > 0 ) {
num_conns--;
ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
goto choose_again;
} else {
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Unable to find a valid connection";
ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
return NULL;
}
}
candidates[ i ].sr_err = lerr;
if ( lerr == LDAP_SUCCESS ) {
META_CANDIDATE_SET( &candidates[ i ] );
@ -1055,6 +1109,10 @@ asyncmeta_clear_one_msc(
msc->msc_time = 0;
msc->msc_binding_time = 0;
msc->msc_result_time = 0;
msc->msc_established_time = 0;
msc->msc_reset_time = slap_get_time();
if ( mt )
mt->msc_reset_time = msc->msc_reset_time;
return 0;
}

View file

@ -231,6 +231,7 @@ asyncmeta_target_finish(
mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_NOANON;
}
mt->msc_reset_time = slap_get_time();
return 0;
}
@ -241,7 +242,7 @@ asyncmeta_back_db_open(
{
a_metainfo_t *mi = (a_metainfo_t *)be->be_private;
char msg[SLAP_TEXT_BUFLEN];
int i;
int i,j;
mi->mi_disabled = 0;
if ( mi->mi_ntargets == 0 ) {
@ -270,6 +271,9 @@ asyncmeta_back_db_open(
if ( mi->mi_ntargets > 0 ) {
mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
for (j = 0; j < mi->mi_ntargets; j++) {
mc->mc_conns[j].mc = mc;
}
} else {
mc->mc_conns = NULL;
}
@ -277,7 +281,6 @@ asyncmeta_back_db_open(
mc->mc_info = mi;
LDAP_STAILQ_INIT( &mc->mc_om_list );
}
ber_dupbv ( &mi->mi_suffix, &be->be_suffix[0] );

View file

@ -1656,15 +1656,44 @@ void asyncmeta_set_msc_time(a_metasingleconn_t *msc)
msc->msc_time = slap_get_time();
}
static void
asyncmeta_update_msc_pending_ops( a_metaconn_t *mc,
bm_context_t *bc)
{
int i;
a_metainfo_t *mi = mc->mc_info;
for (i=0; i<mi->mi_ntargets; i++) {
if ( !META_IS_CANDIDATE( &bc->candidates[ i ] ) ||
bc->candidates[i].sr_msgid == META_MSGID_IGNORE ||
bc->candidates[i].sr_type == REP_RESULT) {
continue;
}
mc->mc_conns[i].msc_pending_ops++;
}
}
static void
asyncmeta_reset_msc_pending_ops( a_metaconn_t *mc )
{
int i;
a_metainfo_t *mi = mc->mc_info;
for (i=0; i<mi->mi_ntargets; i++) {
mc->mc_conns[i].msc_pending_ops = 0;
}
}
void* asyncmeta_timeout_loop(void *ctx, void *arg)
{
struct re_s* rtask = arg;
a_metainfo_t *mi = rtask->arg;
bm_context_t *bc, *onext;
time_t current_time = slap_get_time();
time_t conn_ttl;
time_t conn_reset_interval;
int i, j;
LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list;
LDAP_STAILQ_INIT( &timeout_list );
a_metasingleconn_t* oldest[mi->mi_ntargets];
Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time );
if ( mi->mi_disabled > 0 && asyncmeta_db_has_pending_ops( mi ) == 0 ) {
@ -1676,12 +1705,18 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
return NULL;
}
void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
for (i=0; i<mi->mi_ntargets; i++ ) {
oldest[i] = NULL;
}
for (i=0; i<mi->mi_num_conns; i++) {
a_metaconn_t * mc= &mi->mi_conns[i];
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
asyncmeta_reset_msc_pending_ops(mc);
for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
onext = LDAP_STAILQ_NEXT(bc, bc_next);
if (bc->bc_active > 0) {
asyncmeta_update_msc_pending_ops( mc, bc);
continue;
}
@ -1703,7 +1738,8 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
for (j=0; j<mi->mi_ntargets; j++) {
if (bc->candidates[j].sr_msgid >= 0) {
a_metasingleconn_t *msc = &mc->mc_conns[j];
if ( op->o_tag == LDAP_REQ_SEARCH ) {
if ( op->o_tag == LDAP_REQ_SEARCH &&
!META_BACK_CONN_CLOSING(msc) ) {
msc->msc_active++;
asyncmeta_back_cancel( mc, op,
bc->candidates[ j ].sr_msgid, j );
@ -1730,7 +1766,8 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
if (bc->candidates[j].sr_msgid >= 0) {
a_metasingleconn_t *msc = &mc->mc_conns[j];
asyncmeta_set_msc_time(msc);
if ( op->o_tag == LDAP_REQ_SEARCH ) {
if ( op->o_tag == LDAP_REQ_SEARCH &&
!META_BACK_CONN_CLOSING(msc) ) {
msc->msc_active++;
asyncmeta_back_cancel( mc, op,
bc->candidates[ j ].sr_msgid, j );
@ -1739,7 +1776,17 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
}
}
}
asyncmeta_update_msc_pending_ops( mc, bc);
}
for (j=0; j<mi->mi_ntargets; j++) {
a_metasingleconn_t *msc = &mc->mc_conns[j];
if ( META_BACK_CONN_CLOSING(msc) &&
msc->msc_pending_ops == 0 &&
msc->msc_active <= 0 ) {
asyncmeta_clear_one_msc (mi->mi_targets[j], msc, __FUNCTION__ );
}
}
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) {
@ -1827,9 +1874,36 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
}
}
}
/* find the oldest connection to reset */
for (j=0; j<mi->mi_ntargets; j++) {
a_metasingleconn_t *msc = &mc->mc_conns[j];
if ( msc->msc_established_time > 0 &&
( oldest[j] == NULL || oldest[j]->msc_established_time > msc->msc_established_time ) ) {
oldest[j] = msc;
}
}
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
}
current_time = slap_get_time();
for (j=0; j<mi->mi_ntargets; j++) {
a_metasingleconn_t *msc = oldest[j];
a_metatarget_t *mt = mi->mi_targets[j];
conn_ttl = (mt->mt_conn_ttl > 0)?mt->mt_conn_ttl:mi->mi_conn_ttl;
conn_reset_interval = (mt->mt_conn_reset_interval > 0) ?
mt->mt_conn_reset_interval:mi->mi_conn_reset_interval;
if ( conn_ttl || conn_reset_interval ) {
if ( (current_time - mt->msc_reset_time) <= conn_reset_interval )
continue;
if ( msc != NULL && msc->msc_established_time
&& (msc->msc_established_time + conn_ttl <= current_time) ) {
ldap_pvt_thread_mutex_lock( &msc->mc->mc_om_mutex );
META_BACK_CONN_CLOSING_SET( msc );
ldap_pvt_thread_mutex_unlock( &msc->mc->mc_om_mutex );
}
}
}
slap_sl_mem_setctx(ctx, oldctx);
current_time = slap_get_time();
Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time );

View file

@ -47,6 +47,7 @@ static AttributeDescription *ad_olmDbNextConnectionGroup; /*mi_next_conn*/
/* Target Attributes */
static AttributeDescription *ad_olmTgtURIList; /* mt_uri */
static AttributeDescription *ad_olmTgtQuarantined; /*mt_isquarantined*/
static AttributeDescription *ad_olmTgtConnLastReset; /*msc_reset_time*/
static AttributeDescription *ad_olmTgtTimeoutOps; /*mt_timeout_ops*/
/* Connection Group (a_metaconn_t) attributes */
static AttributeDescription *ad_olmCGID;
@ -55,6 +56,8 @@ static AttributeDescription *ad_olmCGPendingOps;
static AttributeDescription *ad_olmTargetConnLastUseTime; /* msc_time */
static AttributeDescription *ad_olmTargetConnBoundTime; /* msc_binding_time */
static AttributeDescription *ad_olmTargetConnResultTime; /* msc_result_time */
static AttributeDescription *ad_olmTargetConnEstablishedTime; /* msc_established_time */
static AttributeDescription *ad_olmTargetConnResetTime; /* msc_reset_time */
static AttributeDescription *ad_olmTargetConnFlags; /* msc_mscflags */
static AttributeDescription *ad_olmTargetConnURI;
static AttributeDescription *ad_olmTargetConnPeerAddress;
@ -77,6 +80,7 @@ static struct {
{ META_BACK_FCONN_INITED, BER_BVC( "initialized" ) },
{ META_BACK_FCONN_CREATING, BER_BVC( "creating" ) },
{ META_BACK_FCONN_INVALID, BER_BVC( "invalid" ) },
{ META_BACK_FCONN_CLOSING, BER_BVC( "closing" ) },
{ 0 }
};
@ -204,6 +208,33 @@ static struct {
"NO-USER-MODIFICATION "
"USAGE dSAOperation )",
&ad_olmTargetConnPeerAddress },
{ "( olmAsyncmetaAttributes:13 "
"NAME ( 'olmTargetConnEstablishedTime' ) "
"DESC 'Time the connection was established' "
"EQUALITY integerMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
"SINGLE-VALUE "
"NO-USER-MODIFICATION "
"USAGE dSAOperation )",
&ad_olmTargetConnEstablishedTime },
{ "( olmAsyncmetaAttributes:14 "
"NAME ( 'olmTargetConnResetTime' ) "
"DESC 'Last time the connection was reset' "
"EQUALITY integerMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
"SINGLE-VALUE "
"NO-USER-MODIFICATION "
"USAGE dSAOperation )",
&ad_olmTargetConnResetTime },
{ "( olmAsyncmetaAttributes:15 "
"NAME ( 'olmTgtConnLastReset' ) "
"DESC 'Last time a connection to this target was reset' "
"EQUALITY integerMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
"SINGLE-VALUE "
"NO-USER-MODIFICATION "
"USAGE dSAOperation )",
&ad_olmTgtConnLastReset },
{ NULL }
};
@ -235,6 +266,7 @@ static struct {
"MAY ( "
"olmTgtURIList "
"$ olmTgtQuarantined "
"$ olmTgtConnLastReset "
"$ olmTgtTimeoutOps "
") )",
&oc_olmAsyncmetaTarget },
@ -253,9 +285,11 @@ static struct {
"olmTargetConnLastUseTime "
"$ olmTargetConnBoundTime "
"$ olmTargetConnResultTime "
"$ olmTargetConnFlags "
"$ olmTargetConnURI "
"$ olmTargetConnPeerAddress"
"$ olmTargetConnResetTime "
"$ olmTargetConnEstablishedTime "
"$ olmTargetConnFlags "
"$ olmTargetConnURI "
"$ olmTargetConnPeerAddress"
") )",
&oc_olmAsyncmetaTargetConnection },
@ -431,6 +465,18 @@ asyncmeta_back_monitor_target_conn_update(
bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", msc->msc_result_time );
ber_bvreplace( &a->a_vals[ 0 ], &bv );
a = attr_find( e->e_attrs, ad_olmTargetConnResetTime );
assert( a != NULL );
bv.bv_val = buf;
bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", msc->msc_reset_time );
ber_bvreplace( &a->a_vals[ 0 ], &bv );
a = attr_find( e->e_attrs, ad_olmTargetConnEstablishedTime );
assert( a != NULL );
bv.bv_val = buf;
bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", msc->msc_established_time );
ber_bvreplace( &a->a_vals[ 0 ], &bv );
a = attr_find( e->e_attrs, ad_olmTargetConnFlags );
assert( a != NULL );
bv.bv_val = buf;
@ -531,7 +577,7 @@ asyncmeta_back_monitor_target_conn_init(
cb->mc_free = asyncmeta_back_monitor_target_conn_free;
cb->mc_private = (void *)&mc->mc_conns[i];
a = attrs_alloc( 1 + 6 );
a = attrs_alloc( 1 + 8 );
a->a_desc = slap_schema.si_ad_objectClass;
attr_valadd( a, &oc_olmAsyncmetaTargetConnection->soc_cname, NULL, 1 );
@ -559,6 +605,14 @@ asyncmeta_back_monitor_target_conn_init(
next->a_desc = ad_olmTargetConnPeerAddress;
attr_valadd( next, &bv, NULL, 1 );
next = next->a_next;
next->a_desc = ad_olmTargetConnResetTime;
attr_valadd( next, &bv, NULL, 1 );
next = next->a_next;
next->a_desc = ad_olmTargetConnEstablishedTime;
attr_valadd( next, &bv, NULL, 1 );
rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH );
if ( rc != LDAP_SUCCESS )
@ -791,6 +845,12 @@ asyncmeta_back_monitor_targets_update(
bv.bv_len = snprintf( buf, sizeof( buf ), "%i", mt->mt_timeout_ops );
ber_bvreplace( &a->a_vals[ 0 ], &bv );
a = attr_find( e->e_attrs, ad_olmTgtConnLastReset );
assert( a != NULL );
bv.bv_val = buf;
bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", mt->msc_reset_time );
ber_bvreplace( &a->a_vals[ 0 ], &bv );
return SLAP_CB_CONTINUE;
}
@ -866,7 +926,7 @@ asyncmeta_back_monitor_targets_init(
cb->mc_free = asyncmeta_back_monitor_targets_free;
cb->mc_private = (void *)&mi->mi_targets[i];
a = attrs_alloc( 1 + 3 );
a = attrs_alloc( 1 + 4 );
a->a_desc = slap_schema.si_ad_objectClass;
attr_valadd( a, &oc_olmAsyncmetaTarget->soc_cname, NULL, 1 );
@ -880,6 +940,10 @@ asyncmeta_back_monitor_targets_init(
attr_valadd( next, &bv, NULL, 1 );
next = next->a_next;
next->a_desc = ad_olmTgtConnLastReset;
attr_valadd( next, &bv, NULL, 1 );
next = next->a_next;
next->a_desc = ad_olmTgtTimeoutOps;
attr_valadd( next, &bv, NULL, 1 );

View file

@ -0,0 +1,7 @@
dn: cn=Target Connection 1,cn=Connection Group 1,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 2,cn=Connection Group 1,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed

View file

@ -0,0 +1,7 @@
dn: cn=Target Connection 1,cn=Connection Group 2,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 2,cn=Connection Group 2,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed

View file

@ -0,0 +1,31 @@
dn: cn=Connections,cn=database 1,cn=databases,cn=monitor
dn: cn=Connection Group 1,cn=Connections,cn=database 1,cn=databases,cn=monitor
dn: cn=Target Connection 1,cn=Connection Group 1,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: anonymous,initialized
dn: cn=Target Connection 2,cn=Connection Group 1,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: anonymous,initialized
dn: cn=Connection Group 2,cn=Connections,cn=database 1,cn=databases,cn=monitor
dn: cn=Target Connection 1,cn=Connection Group 2,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: anonymous,initialized
dn: cn=Target Connection 2,cn=Connection Group 2,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: anonymous,initialized
dn: cn=Connection Group 3,cn=Connections,cn=database 1,cn=databases,cn=monitor
dn: cn=Target Connection 1,cn=Connection Group 3,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: anonymous,initialized
dn: cn=Target Connection 2,cn=Connection Group 3,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: anonymous,initialized

View file

@ -0,0 +1,23 @@
dn: cn=Target Connection 1,cn=Connection Group 1,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 2,cn=Connection Group 1,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 1,cn=Connection Group 2,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 2,cn=Connection Group 2,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 1,cn=Connection Group 3,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed
dn: cn=Target Connection 2,cn=Connection Group 3,cn=Connections,cn=database 1,
cn=databases,cn=monitor
olmTargetConnFlags: closed

View file

@ -0,0 +1,79 @@
# provider slapd config -- for testing
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2025 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
include @SCHEMADIR@/core.schema
include @SCHEMADIR@/cosine.schema
include @SCHEMADIR@/inetorgperson.schema
include @SCHEMADIR@/openldap.schema
include @SCHEMADIR@/nis.schema
pidfile @TESTDIR@/slapd.m.pid
argsfile @TESTDIR@/slapd.m.args
#ldapmod#modulepath ../servers/slapd/back-ldap/
#ldapmod#moduleload back_ldap.la
#asyncmetamod#modulepath ../servers/slapd/back-asyncmeta/
#asyncmetamod#moduleload back_asyncmeta.la
# seems to improve behavior under very heavy load
# (i.e. it alleviates load on target systems)
threads 8
#######################################################################
# database definitions
#######################################################################
database asyncmeta
suffix "o=Example,c=US"
rootdn "cn=Manager,o=Example,c=US"
rootpw secret
chase-referrals no
#nretries forever
nretries 100
#norefs true
network-timeout 500
#max-timeout-ops 50
#max-pending-ops 128
max-target-conns 3
conn-ttl 10s 5s
monitoring on
# local
uri "@URI2@ou=Meta,o=Example,c=US"
subtree-exclude "ou=Excluded,ou=Meta,o=Example,c=US"
suffixmassage "ou=Meta,o=Example,c=US" "ou=Meta,dc=example,dc=com"
###pseudorootdn "cn=manager,ou=meta,dc=example,dc=com"
###pseudorootpw secret
idassert-bind bindmethod=simple
binddn="cn=manager,ou=meta,dc=example,dc=com"
credentials="secret"
mode=self
flags=non-prescriptive
idassert-authzFrom "dn.exact:cn=Manager,o=Local"
# remote
uri "@URI1@o=Example,c=US"
subtree-include "dn.subtree:o=Example,c=US"
suffixmassage "o=Example,c=US" "dc=example,dc=com"
###pseudorootdn "cn=manager,dc=example,dc=com"
###pseudorootpw secret
idassert-bind bindmethod=simple
binddn="cn=manager,dc=example,dc=com"
credentials="secret"
mode=self
flags=non-prescriptive
idassert-authzFrom "dn.exact:cn=Manager,o=Local"
database monitor

View file

@ -166,6 +166,7 @@ METACONF=$DATADIR/slapd-meta.conf
METACONF1=$DATADIR/slapd-meta-target1.conf
METACONF2=$DATADIR/slapd-meta-target2.conf
ASYNCMETACONF=$DATADIR/slapd-asyncmeta.conf
ASYNCMETACONF2=$DATADIR/slapd-asyncmeta-conttl.conf
GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf
ACICONF=$DATADIR/slapd-aci.conf
VALSORTCONF=$DATADIR/slapd-valsort.conf

View file

@ -0,0 +1,295 @@
#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2025 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
echo "running defines.sh"
. $SRCDIR/scripts/defines.sh
echo ""
if test $BACKASYNCMETA = asyncmetano ; then
echo "asyncmeta backend not available, test skipped"
exit 0
fi
if test $BACKLDAP = ldapno ; then
echo "ldap backend not available, test skipped"
exit 0
fi
rm -rf $TESTDIR
mkdir -p $TESTDIR $DBDIR1 $DBDIR2
$SLAPPASSWD -g -n >$CONFIGPWF
echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
echo "Starting slapd on TCP/IP port $PORT1..."
. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
PID=$!
if test $WAIT != 0 ; then
echo PID $PID
read foo
fi
KILLPIDS="$PID"
sleep 1
echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
$LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
'objectclass=*' > /dev/null 2>&1
RC=$?
if test $RC = 0 ; then
break
fi
echo "Waiting 5 seconds for slapd to start..."
sleep 5
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Using ldapadd to populate the database..."
$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
$LDIFORDERED > $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Starting slapd on TCP/IP port $PORT2..."
. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
PID=$!
if test $WAIT != 0 ; then
echo PID $PID
read foo
fi
KILLPIDS="$KILLPIDS $PID"
sleep 1
echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
$LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
'objectclass=*' > /dev/null 2>&1
RC=$?
if test $RC = 0 ; then
break
fi
echo "Waiting 5 seconds for slapd to start..."
sleep 5
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Using ldapadd to populate the database..."
$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
$LDIFMETA >> $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Starting slapd on TCP/IP port $PORT3..."
. $CONFFILTER $BACKEND < $ASYNCMETACONF2 > $CONF3
$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
PID=$!
if test $WAIT != 0 ; then
echo PID $PID
read foo
fi
KILLPIDS="$KILLPIDS $PID"
sleep 1
echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
$LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
'objectclass=*' > /dev/null 2>&1
RC=$?
if test $RC = 0 ; then
break
fi
echo "Waiting 5 seconds for slapd to start..."
sleep 5
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
cat /dev/null > $SEARCHOUT
#search cn=monitor, all connections are closed
SEARCHDN="cn=Connections,cn=database 1,cn=databases,cn=monitor"
echo "Verifying that all target connections are closed..."
cat /dev/null > $SEARCHOUT
echo " base=\"$SEARCHDN\"..."
echo "# base=\"$SEARCHDN\"..." >> $SEARCHOUT
$LDAPSEARCH -H $URI3 \
-b "$SEARCHDN" \
"olmTargetConnFlags=closed" 'olmTargetConnFlags' >> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Unable to read monitor ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
$LDIFFILTER < data/asyncmeta.closed.out > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
#run 3 searches
for i in 0 1 2; do
BASEDN="o=Example,c=US"
echo "Searching base=\"$BASEDN\"..."
echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
RC=$?
#if test $RC != 0 ; then
# echo "Search failed ($RC)!"
# test $KILLSERVERS != no && kill -HUP $KILLPIDS
# exit $RC
#fi
case $RC in
0)
;;
51)
echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 0
;;
*)
echo "Search failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
;;
esac
sleep 2
done
# search cn=monitor - no connections should be closed yet
SEARCHDN="cn=Connections,cn=database 1,cn=databases,cn=monitor"
echo "Verifying that all target connections are open..."
cat /dev/null > $SEARCHOUT
echo " base=\"$SEARCHDN\"..."
echo "# base=\"$SEARCHDN\"..." >> $SEARCHOUT
$LDAPSEARCH -H $URI3 \
-b "$SEARCHDN" \
'olmTargetConnFlags' >> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Unable to read monitor ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
$LDIFFILTER < data/asyncmeta.allopen.out > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
# wait 6 seconds and search cn=monitor - connection group 1 is closed
SEARCHDN="cn=Connections,cn=database 1,cn=databases,cn=monitor"
echo "Verifying that connection group 1 is closed..."
sleep 5
cat /dev/null > $SEARCHOUT
echo " base=\"$SEARCHDN\"..."
echo "# base=\"$SEARCHDN\"..." >> $SEARCHOUT
$LDAPSEARCH -H $URI3 \
-b "$SEARCHDN" \
"olmTargetConnFlags=closed" 'olmTargetConnFlags' >> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Unable to read monitor ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
$LDIFFILTER < data/asyncmeta.1.out > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
SEARCHDN="cn=Connections,cn=database 1,cn=databases,cn=monitor"
echo "Verifying that target connection group 2 is closed..."
sleep 6
cat /dev/null > $SEARCHOUT
echo " base=\"$SEARCHDN\"..."
echo "# base=\"$SEARCHDN\"..." >> $SEARCHOUT
$LDAPSEARCH -H $URI3 \
-b "cn=Connection Group 2,$SEARCHDN" \
"olmTargetConnFlags=closed" 'olmTargetConnFlags' >> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Unable to read monitor ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
$LDIFFILTER < data/asyncmeta.2.out > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
SEARCHDN="cn=Connections,cn=database 1,cn=databases,cn=monitor"
echo "Verifying that all target connections are closed..."
# wait 6 seconds, search, all connections should be closed
sleep 6
cat /dev/null > $SEARCHOUT
echo " base=\"$SEARCHDN\"..."
echo "# base=\"$SEARCHDN\"..." >> $SEARCHOUT
$LDAPSEARCH -H $URI3 \
-b "$SEARCHDN" \
"olmTargetConnFlags=closed" 'olmTargetConnFlags' >> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Unable to read monitor ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
$LDIFFILTER < data/asyncmeta.closed.out > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
cat /dev/null > $SEARCHOUT
test $KILLSERVERS != no && kill -HUP $KILLPIDS
echo ">>>>> Test succeeded"
test $KILLSERVERS != no && wait
exit 0