mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-20 22:59:34 -05:00
ITS#10218 Disabling and re-enabling an asyncmeta database via cn=config leaks memory
Make sure asyncmeta frees the pending operations structures, resets all connections, frees connection structures and stops the timeout-loop.
This commit is contained in:
parent
f0ab743db4
commit
5740d1747d
3 changed files with 75 additions and 48 deletions
|
|
@ -427,6 +427,7 @@ typedef struct a_metainfo_t {
|
||||||
a_metaconn_t *mi_conns;
|
a_metaconn_t *mi_conns;
|
||||||
|
|
||||||
struct berval mi_suffix;
|
struct berval mi_suffix;
|
||||||
|
volatile int mi_disabled;
|
||||||
} a_metainfo_t;
|
} a_metainfo_t;
|
||||||
|
|
||||||
typedef enum meta_op_type {
|
typedef enum meta_op_type {
|
||||||
|
|
@ -780,6 +781,9 @@ asyncmeta_db_has_mscs(a_metainfo_t *mi);
|
||||||
void
|
void
|
||||||
asyncmeta_target_free(a_metatarget_t *mt);
|
asyncmeta_target_free(a_metatarget_t *mt);
|
||||||
|
|
||||||
|
void
|
||||||
|
asyncmeta_back_clear_miconns(a_metainfo_t *mi);
|
||||||
|
|
||||||
/* The the maximum time in seconds after a result has been received on a connection,
|
/* The the maximum time in seconds after a result has been received on a connection,
|
||||||
* after which it can be reset if a sender error occurs. Should this be configurable? */
|
* after which it can be reset if a sender error occurs. Should this be configurable? */
|
||||||
#define META_BACK_RESULT_INTERVAL (2)
|
#define META_BACK_RESULT_INTERVAL (2)
|
||||||
|
|
|
||||||
|
|
@ -240,13 +240,13 @@ asyncmeta_back_db_open(
|
||||||
char msg[SLAP_TEXT_BUFLEN];
|
char msg[SLAP_TEXT_BUFLEN];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
mi->mi_disabled = 0;
|
||||||
if ( mi->mi_ntargets == 0 ) {
|
if ( mi->mi_ntargets == 0 ) {
|
||||||
|
|
||||||
Debug( LDAP_DEBUG_ANY,
|
Debug( LDAP_DEBUG_ANY,
|
||||||
"asyncmeta_back_db_open: no targets defined\n" );
|
"asyncmeta_back_db_open: no targets defined\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
mi->mi_num_conns = 0;
|
|
||||||
for ( i = 0; i < mi->mi_ntargets; i++ ) {
|
for ( i = 0; i < mi->mi_ntargets; i++ ) {
|
||||||
a_metatarget_t *mt = mi->mi_targets[ i ];
|
a_metatarget_t *mt = mi->mi_targets[ i ];
|
||||||
if ( asyncmeta_target_finish( mi, mt,
|
if ( asyncmeta_target_finish( mi, mt,
|
||||||
|
|
@ -255,31 +255,34 @@ asyncmeta_back_db_open(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns;
|
if ( mi->mi_conns == NULL ) {
|
||||||
assert(mi->mi_num_conns > 0);
|
mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns;
|
||||||
mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t ));
|
assert(mi->mi_num_conns > 0);
|
||||||
for (i = 0; i < mi->mi_num_conns; i++) {
|
mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t ));
|
||||||
a_metaconn_t *mc = &mi->mi_conns[i];
|
for (i = 0; i < mi->mi_num_conns; i++) {
|
||||||
ldap_pvt_thread_mutex_init( &mc->mc_om_mutex);
|
a_metaconn_t *mc = &mi->mi_conns[i];
|
||||||
mc->mc_authz_target = META_BOUND_NONE;
|
ldap_pvt_thread_mutex_init( &mc->mc_om_mutex);
|
||||||
|
mc->mc_authz_target = META_BOUND_NONE;
|
||||||
|
|
||||||
if ( mi->mi_ntargets > 0 ) {
|
if ( mi->mi_ntargets > 0 ) {
|
||||||
mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
|
mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
|
||||||
} else {
|
} else {
|
||||||
mc->mc_conns = NULL;
|
mc->mc_conns = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mc->mc_info = mi;
|
||||||
|
LDAP_STAILQ_INIT( &mc->mc_om_list );
|
||||||
}
|
}
|
||||||
|
|
||||||
mc->mc_info = mi;
|
|
||||||
LDAP_STAILQ_INIT( &mc->mc_om_list );
|
|
||||||
}
|
|
||||||
|
|
||||||
ber_dupbv ( &mi->mi_suffix, &be->be_suffix[0] );
|
|
||||||
|
|
||||||
if ( ( slapMode & SLAP_SERVER_MODE ) && mi->mi_ntargets > 0 ) {
|
ber_dupbv ( &mi->mi_suffix, &be->be_suffix[0] );
|
||||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
|
||||||
mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 1,
|
if ( ( slapMode & SLAP_SERVER_MODE ) && mi->mi_ntargets > 0 ) {
|
||||||
asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val );
|
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 1,
|
||||||
|
asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val );
|
||||||
|
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -301,28 +304,26 @@ asyncmeta_back_conn_free(
|
||||||
free( mc );
|
free( mc );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
asyncmeta_back_stop_miconns( a_metainfo_t *mi )
|
|
||||||
{
|
|
||||||
|
|
||||||
/*Todo do any other mc cleanup here if necessary*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
asyncmeta_back_clear_miconns( a_metainfo_t *mi )
|
asyncmeta_back_clear_miconns( a_metainfo_t *mi )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
a_metaconn_t *mc;
|
a_metaconn_t *mc;
|
||||||
for (i = 0; i < mi->mi_num_conns; i++) {
|
if ( mi->mi_conns != NULL ) {
|
||||||
mc = &mi->mi_conns[i];
|
for (i = 0; i < mi->mi_num_conns; i++) {
|
||||||
/* todo clear the message queue */
|
mc = &mi->mi_conns[i];
|
||||||
for (j = 0; j < mi->mi_ntargets; j ++) {
|
for (j = 0; j < mi->mi_ntargets; j ++) {
|
||||||
asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
|
asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mc->mc_conns )
|
||||||
|
free( mc->mc_conns );
|
||||||
|
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
|
||||||
}
|
}
|
||||||
free(mc->mc_conns);
|
free(mi->mi_conns);
|
||||||
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
|
|
||||||
}
|
}
|
||||||
free(mi->mi_conns);
|
mi->mi_conns = NULL;
|
||||||
|
mi->mi_num_conns = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -392,17 +393,22 @@ asyncmeta_back_db_close(
|
||||||
|
|
||||||
if ( be->be_private ) {
|
if ( be->be_private ) {
|
||||||
mi = ( a_metainfo_t * )be->be_private;
|
mi = ( a_metainfo_t * )be->be_private;
|
||||||
if ( mi->mi_task != NULL ) {
|
mi->mi_disabled = 1;
|
||||||
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
/* there are no pending ops so we can free up the connections and stop the timeout loop
|
||||||
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, mi->mi_task )) {
|
* else timeout_loop will clear up the ops and connections and not reschedule */
|
||||||
ldap_pvt_runqueue_stoptask( &slapd_rq, mi->mi_task);
|
if ( asyncmeta_db_has_pending_ops( mi ) == 0 ) {
|
||||||
}
|
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
|
||||||
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
asyncmeta_back_clear_miconns(mi);
|
||||||
mi->mi_task = NULL;
|
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
|
||||||
|
if ( mi->mi_task != NULL ) {
|
||||||
|
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
|
||||||
|
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, mi->mi_task )) {
|
||||||
|
ldap_pvt_runqueue_stoptask( &slapd_rq, mi->mi_task);
|
||||||
|
}
|
||||||
|
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
|
||||||
|
mi->mi_task = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
|
|
||||||
asyncmeta_back_stop_miconns( mi );
|
|
||||||
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1487,6 +1487,11 @@ asyncmeta_op_handle_result(void *ctx, void *arg)
|
||||||
bm_context_t *bc;
|
bm_context_t *bc;
|
||||||
void *oldctx;
|
void *oldctx;
|
||||||
|
|
||||||
|
/* exit if the database is disabled, this will let timeout_loop
|
||||||
|
* do it's job faster */
|
||||||
|
if ( mc->mc_info->mi_disabled > 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
|
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
|
||||||
rc = ++mc->mc_active;
|
rc = ++mc->mc_active;
|
||||||
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
|
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
|
||||||
|
|
@ -1661,6 +1666,14 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
|
||||||
LDAP_STAILQ_INIT( &timeout_list );
|
LDAP_STAILQ_INIT( &timeout_list );
|
||||||
|
|
||||||
Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time );
|
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 ) {
|
||||||
|
Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] database disabled, clearing connections [%ld] \n", rtask, current_time );
|
||||||
|
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
|
||||||
|
asyncmeta_back_clear_miconns( mi );
|
||||||
|
mi->mi_task = NULL;
|
||||||
|
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
|
void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
|
||||||
for (i=0; i<mi->mi_num_conns; i++) {
|
for (i=0; i<mi->mi_num_conns; i++) {
|
||||||
a_metaconn_t * mc= &mi->mi_conns[i];
|
a_metaconn_t * mc= &mi->mi_conns[i];
|
||||||
|
|
@ -1671,6 +1684,10 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mi->mi_disabled > 0) {
|
||||||
|
bc->bc_invalid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (bc->op->o_abandon ) {
|
if (bc->op->o_abandon ) {
|
||||||
Operation *op = bc->op;
|
Operation *op = bc->op;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue