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:
Nadezhda Ivanova 2024-05-23 15:54:04 +03:00 committed by Quanah Gibson-Mount
parent f0ab743db4
commit 5740d1747d
3 changed files with 75 additions and 48 deletions

View file

@ -427,6 +427,7 @@ typedef struct a_metainfo_t {
a_metaconn_t *mi_conns;
struct berval mi_suffix;
volatile int mi_disabled;
} a_metainfo_t;
typedef enum meta_op_type {
@ -780,6 +781,9 @@ asyncmeta_db_has_mscs(a_metainfo_t *mi);
void
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,
* after which it can be reset if a sender error occurs. Should this be configurable? */
#define META_BACK_RESULT_INTERVAL (2)

View file

@ -240,13 +240,13 @@ asyncmeta_back_db_open(
char msg[SLAP_TEXT_BUFLEN];
int i;
mi->mi_disabled = 0;
if ( mi->mi_ntargets == 0 ) {
Debug( LDAP_DEBUG_ANY,
"asyncmeta_back_db_open: no targets defined\n" );
}
mi->mi_num_conns = 0;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
a_metatarget_t *mt = mi->mi_targets[ i ];
if ( asyncmeta_target_finish( mi, mt,
@ -255,6 +255,7 @@ asyncmeta_back_db_open(
}
}
if ( mi->mi_conns == NULL ) {
mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns;
assert(mi->mi_num_conns > 0);
mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t ));
@ -273,6 +274,7 @@ asyncmeta_back_db_open(
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 ) {
@ -281,6 +283,7 @@ asyncmeta_back_db_open(
asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
}
return 0;
}
@ -301,28 +304,26 @@ asyncmeta_back_conn_free(
free( mc );
}
static void
asyncmeta_back_stop_miconns( a_metainfo_t *mi )
{
/*Todo do any other mc cleanup here if necessary*/
}
static void
void
asyncmeta_back_clear_miconns( a_metainfo_t *mi )
{
int i, j;
a_metaconn_t *mc;
if ( mi->mi_conns != NULL ) {
for (i = 0; i < mi->mi_num_conns; i++) {
mc = &mi->mi_conns[i];
/* todo clear the message queue */
for (j = 0; j < mi->mi_ntargets; j ++) {
asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
}
free(mc->mc_conns);
if ( mc->mc_conns )
free( mc->mc_conns );
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
}
free(mi->mi_conns);
}
mi->mi_conns = NULL;
mi->mi_num_conns = 0;
}
void
@ -392,6 +393,13 @@ asyncmeta_back_db_close(
if ( be->be_private ) {
mi = ( a_metainfo_t * )be->be_private;
mi->mi_disabled = 1;
/* there are no pending ops so we can free up the connections and stop the timeout loop
* else timeout_loop will clear up the ops and connections and not reschedule */
if ( asyncmeta_db_has_pending_ops( mi ) == 0 ) {
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
asyncmeta_back_clear_miconns(mi);
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 )) {
@ -400,9 +408,7 @@ asyncmeta_back_db_close(
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;
}

View file

@ -1487,6 +1487,11 @@ asyncmeta_op_handle_result(void *ctx, void *arg)
bm_context_t *bc;
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 );
rc = ++mc->mc_active;
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 );
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);
for (i=0; i<mi->mi_num_conns; i++) {
a_metaconn_t * mc= &mi->mi_conns[i];
@ -1671,6 +1684,10 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg)
continue;
}
if (mi->mi_disabled > 0) {
bc->bc_invalid = 1;
}
if (bc->op->o_abandon ) {
Operation *op = bc->op;