Home | History | Annotate | Line # | Download | only in back-monitor
      1  1.3  christos /*	$NetBSD: cache.c,v 1.4 2025/09/05 21:16:28 christos Exp $	*/
      2  1.2  christos 
      3  1.1     lukem /* cache.c - routines to maintain an in-core cache of entries */
      4  1.2  christos /* $OpenLDAP$ */
      5  1.1     lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  1.1     lukem  *
      7  1.4  christos  * Copyright 2001-2024 The OpenLDAP Foundation.
      8  1.1     lukem  * Portions Copyright 2001-2003 Pierangelo Masarati.
      9  1.1     lukem  * All rights reserved.
     10  1.1     lukem  *
     11  1.1     lukem  * Redistribution and use in source and binary forms, with or without
     12  1.1     lukem  * modification, are permitted only as authorized by the OpenLDAP
     13  1.1     lukem  * Public License.
     14  1.1     lukem  *
     15  1.1     lukem  * A copy of this license is available in file LICENSE in the
     16  1.1     lukem  * top-level directory of the distribution or, alternatively, at
     17  1.1     lukem  * <http://www.OpenLDAP.org/license.html>.
     18  1.1     lukem  */
     19  1.1     lukem /* ACKNOWLEDGEMENTS:
     20  1.1     lukem  * This work was initially developed by Pierangelo Masarati for inclusion
     21  1.1     lukem  * in OpenLDAP Software.
     22  1.1     lukem  */
     23  1.1     lukem 
     24  1.2  christos #include <sys/cdefs.h>
     25  1.3  christos __RCSID("$NetBSD: cache.c,v 1.4 2025/09/05 21:16:28 christos Exp $");
     26  1.2  christos 
     27  1.1     lukem #include "portable.h"
     28  1.1     lukem 
     29  1.1     lukem #include <stdio.h>
     30  1.1     lukem #include "ac/string.h"
     31  1.1     lukem 
     32  1.1     lukem #include "slap.h"
     33  1.1     lukem 
     34  1.1     lukem #include "back-monitor.h"
     35  1.1     lukem 
     36  1.1     lukem /*
     37  1.1     lukem  * The cache maps DNs to Entries.
     38  1.1     lukem  * Each entry, on turn, holds the list of its children in the e_private field.
     39  1.1     lukem  * This is used by search operation to perform onelevel and subtree candidate
     40  1.1     lukem  * selection.
     41  1.1     lukem  */
     42  1.1     lukem typedef struct monitor_cache_t {
     43  1.1     lukem 	struct berval		mc_ndn;
     44  1.1     lukem 	Entry   		*mc_e;
     45  1.1     lukem } monitor_cache_t;
     46  1.1     lukem 
     47  1.1     lukem /*
     48  1.1     lukem  * compares entries based on the dn
     49  1.1     lukem  */
     50  1.1     lukem int
     51  1.1     lukem monitor_cache_cmp(
     52  1.1     lukem 	const void	*c1,
     53  1.1     lukem 	const void	*c2 )
     54  1.1     lukem {
     55  1.1     lukem 	monitor_cache_t 	*cc1 = ( monitor_cache_t * )c1;
     56  1.1     lukem 	monitor_cache_t 	*cc2 = ( monitor_cache_t * )c2;
     57  1.1     lukem 
     58  1.1     lukem 	/*
     59  1.1     lukem 	 * case sensitive, because the dn MUST be normalized
     60  1.1     lukem 	 */
     61  1.1     lukem 	return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn );
     62  1.1     lukem }
     63  1.1     lukem 
     64  1.1     lukem /*
     65  1.1     lukem  * checks for duplicate entries
     66  1.1     lukem  */
     67  1.1     lukem int
     68  1.1     lukem monitor_cache_dup(
     69  1.1     lukem 	void		*c1,
     70  1.1     lukem 	void		*c2 )
     71  1.1     lukem {
     72  1.1     lukem 	monitor_cache_t *cc1 = ( monitor_cache_t * )c1;
     73  1.1     lukem 	monitor_cache_t *cc2 = ( monitor_cache_t * )c2;
     74  1.1     lukem 
     75  1.1     lukem 	/*
     76  1.1     lukem 	 * case sensitive, because the dn MUST be normalized
     77  1.1     lukem 	 */
     78  1.1     lukem 	return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn ) == 0 ? -1 : 0;
     79  1.1     lukem }
     80  1.1     lukem 
     81  1.1     lukem /*
     82  1.1     lukem  * adds an entry to the cache and inits the mutex
     83  1.1     lukem  */
     84  1.1     lukem int
     85  1.1     lukem monitor_cache_add(
     86  1.1     lukem 	monitor_info_t	*mi,
     87  1.4  christos 	Entry		*e,
     88  1.4  christos 	Entry		*parent )
     89  1.1     lukem {
     90  1.4  christos 	monitor_cache_t tmp_mc, *mc, *pmc = NULL;
     91  1.4  christos 	Entry **ep = NULL, *prev = NULL;
     92  1.4  christos 	int		rc = -1;
     93  1.1     lukem 
     94  1.1     lukem 	assert( mi != NULL );
     95  1.1     lukem 	assert( e != NULL );
     96  1.1     lukem 
     97  1.4  christos 	dnParent( &e->e_nname, &tmp_mc.mc_ndn );
     98  1.4  christos 
     99  1.1     lukem 	mc = ( monitor_cache_t * )ch_malloc( sizeof( monitor_cache_t ) );
    100  1.1     lukem 	mc->mc_ndn = e->e_nname;
    101  1.1     lukem 	mc->mc_e = e;
    102  1.4  christos 
    103  1.4  christos 	if ( parent ) {
    104  1.4  christos 		/* Shortcut, but follow lock order as a fallback */
    105  1.4  christos 		if ( ldap_pvt_thread_mutex_trylock( &mi->mi_cache_lock ) ) {
    106  1.4  christos 			monitor_cache_release( mi, parent );
    107  1.4  christos 			ldap_pvt_thread_mutex_lock( &mi->mi_cache_lock );
    108  1.4  christos 			monitor_cache_lock( parent );
    109  1.4  christos 		}
    110  1.4  christos 	} else {
    111  1.4  christos 		ldap_pvt_thread_mutex_lock( &mi->mi_cache_lock );
    112  1.4  christos 	}
    113  1.4  christos 
    114  1.4  christos 	/* Allow database root be added */
    115  1.4  christos 	if ( parent == NULL && mi->mi_cache != NULL ) {
    116  1.4  christos 		pmc = ldap_avl_find( mi->mi_cache, &tmp_mc, monitor_cache_cmp );
    117  1.4  christos 		if ( pmc == NULL ) {
    118  1.4  christos 			goto done;
    119  1.4  christos 		}
    120  1.4  christos 		parent = pmc->mc_e;
    121  1.4  christos 		monitor_cache_lock( parent );
    122  1.4  christos 	}
    123  1.4  christos 
    124  1.4  christos 	rc = ldap_avl_insert( &mi->mi_cache, mc,
    125  1.1     lukem 			monitor_cache_cmp, monitor_cache_dup );
    126  1.4  christos 	if ( rc != LDAP_SUCCESS ) {
    127  1.4  christos 		goto done;
    128  1.4  christos 	}
    129  1.4  christos 
    130  1.4  christos 	if ( parent != NULL ) {
    131  1.4  christos 		monitor_entry_t *mp = parent->e_private;
    132  1.4  christos 
    133  1.4  christos 		if ( mp->mp_children ) {
    134  1.4  christos 			monitor_entry_t *tail;
    135  1.4  christos 
    136  1.4  christos 			monitor_cache_lock( mp->mp_last );
    137  1.4  christos 			tail = mp->mp_last->e_private;
    138  1.4  christos 			tail->mp_next = e;
    139  1.4  christos 			monitor_cache_release( mi, mp->mp_last );
    140  1.4  christos 			mp->mp_last = e;
    141  1.4  christos 		} else {
    142  1.4  christos 			mp->mp_children = mp->mp_last = e;
    143  1.4  christos 		}
    144  1.4  christos 	}
    145  1.1     lukem 
    146  1.4  christos done:
    147  1.4  christos 	if ( pmc != NULL ) {
    148  1.4  christos 		monitor_cache_release( mi, parent );
    149  1.4  christos 	}
    150  1.4  christos 	ldap_pvt_thread_mutex_unlock( &mi->mi_cache_lock );
    151  1.4  christos 
    152  1.4  christos 	if ( rc != LDAP_SUCCESS ) {
    153  1.4  christos 		ch_free( mc );
    154  1.4  christos 	}
    155  1.1     lukem 	return rc;
    156  1.1     lukem }
    157  1.1     lukem 
    158  1.1     lukem /*
    159  1.1     lukem  * locks the entry (no r/w)
    160  1.1     lukem  */
    161  1.1     lukem int
    162  1.1     lukem monitor_cache_lock(
    163  1.1     lukem 	Entry		*e )
    164  1.1     lukem {
    165  1.1     lukem 	monitor_entry_t *mp;
    166  1.1     lukem 
    167  1.1     lukem 	assert( e != NULL );
    168  1.1     lukem 	assert( e->e_private != NULL );
    169  1.1     lukem 
    170  1.1     lukem 	mp = ( monitor_entry_t * )e->e_private;
    171  1.1     lukem 	ldap_pvt_thread_mutex_lock( &mp->mp_mutex );
    172  1.1     lukem 
    173  1.1     lukem 	return( 0 );
    174  1.1     lukem }
    175  1.1     lukem 
    176  1.1     lukem /*
    177  1.1     lukem  * tries to lock the entry (no r/w)
    178  1.1     lukem  */
    179  1.1     lukem int
    180  1.1     lukem monitor_cache_trylock(
    181  1.1     lukem 	Entry		*e )
    182  1.1     lukem {
    183  1.1     lukem 	monitor_entry_t *mp;
    184  1.1     lukem 
    185  1.1     lukem 	assert( e != NULL );
    186  1.1     lukem 	assert( e->e_private != NULL );
    187  1.1     lukem 
    188  1.1     lukem 	mp = ( monitor_entry_t * )e->e_private;
    189  1.1     lukem 	return ldap_pvt_thread_mutex_trylock( &mp->mp_mutex );
    190  1.1     lukem }
    191  1.1     lukem 
    192  1.1     lukem /*
    193  1.1     lukem  * gets an entry from the cache based on the normalized dn
    194  1.1     lukem  * with mutex locked
    195  1.1     lukem  */
    196  1.1     lukem int
    197  1.1     lukem monitor_cache_get(
    198  1.1     lukem 	monitor_info_t	*mi,
    199  1.1     lukem 	struct berval	*ndn,
    200  1.1     lukem 	Entry		**ep )
    201  1.1     lukem {
    202  1.1     lukem 	monitor_cache_t tmp_mc, *mc;
    203  1.1     lukem 
    204  1.1     lukem 	assert( mi != NULL );
    205  1.1     lukem 	assert( ndn != NULL );
    206  1.1     lukem 	assert( ep != NULL );
    207  1.1     lukem 
    208  1.1     lukem 	*ep = NULL;
    209  1.1     lukem 
    210  1.1     lukem 	tmp_mc.mc_ndn = *ndn;
    211  1.4  christos 
    212  1.4  christos 	ldap_pvt_thread_mutex_lock( &mi->mi_cache_lock );
    213  1.3  christos 	mc = ( monitor_cache_t * )ldap_avl_find( mi->mi_cache,
    214  1.1     lukem 			( caddr_t )&tmp_mc, monitor_cache_cmp );
    215  1.1     lukem 
    216  1.1     lukem 	if ( mc != NULL ) {
    217  1.1     lukem 		/* entry is returned with mutex locked */
    218  1.4  christos 		monitor_cache_lock( mc->mc_e );
    219  1.1     lukem 		*ep = mc->mc_e;
    220  1.1     lukem 	}
    221  1.1     lukem 
    222  1.4  christos 	ldap_pvt_thread_mutex_unlock( &mi->mi_cache_lock );
    223  1.1     lukem 
    224  1.1     lukem 	return ( *ep == NULL ? -1 : 0 );
    225  1.1     lukem }
    226  1.1     lukem 
    227  1.1     lukem /*
    228  1.1     lukem  * gets an entry from the cache based on the normalized dn
    229  1.1     lukem  * with mutex locked
    230  1.1     lukem  */
    231  1.1     lukem int
    232  1.1     lukem monitor_cache_remove(
    233  1.1     lukem 	monitor_info_t	*mi,
    234  1.1     lukem 	struct berval	*ndn,
    235  1.1     lukem 	Entry		**ep )
    236  1.1     lukem {
    237  1.1     lukem 	monitor_cache_t tmp_mc, *mc;
    238  1.1     lukem 	struct berval	pndn;
    239  1.1     lukem 
    240  1.1     lukem 	assert( mi != NULL );
    241  1.1     lukem 	assert( ndn != NULL );
    242  1.1     lukem 	assert( ep != NULL );
    243  1.1     lukem 
    244  1.1     lukem 	*ep = NULL;
    245  1.1     lukem 
    246  1.1     lukem 	dnParent( ndn, &pndn );
    247  1.1     lukem 
    248  1.1     lukem retry:;
    249  1.4  christos 	ldap_pvt_thread_mutex_lock( &mi->mi_cache_lock );
    250  1.1     lukem 
    251  1.1     lukem 	tmp_mc.mc_ndn = *ndn;
    252  1.3  christos 	mc = ( monitor_cache_t * )ldap_avl_find( mi->mi_cache,
    253  1.1     lukem 			( caddr_t )&tmp_mc, monitor_cache_cmp );
    254  1.1     lukem 
    255  1.1     lukem 	if ( mc != NULL ) {
    256  1.1     lukem 		monitor_cache_t *pmc;
    257  1.1     lukem 
    258  1.1     lukem 		tmp_mc.mc_ndn = pndn;
    259  1.3  christos 		pmc = ( monitor_cache_t * )ldap_avl_find( mi->mi_cache,
    260  1.1     lukem 			( caddr_t )&tmp_mc, monitor_cache_cmp );
    261  1.1     lukem 		if ( pmc != NULL ) {
    262  1.1     lukem 			monitor_entry_t	*mp = (monitor_entry_t *)mc->mc_e->e_private,
    263  1.1     lukem 					*pmp = (monitor_entry_t *)pmc->mc_e->e_private;
    264  1.4  christos 			Entry		**entryp, *prev = NULL;
    265  1.1     lukem 
    266  1.4  christos 			monitor_cache_lock( pmc->mc_e );
    267  1.1     lukem 
    268  1.1     lukem 			for ( entryp = &pmp->mp_children; *entryp != NULL;  ) {
    269  1.1     lukem 				monitor_entry_t	*next = (monitor_entry_t *)(*entryp)->e_private;
    270  1.4  christos 
    271  1.4  christos 				monitor_cache_lock( *entryp );
    272  1.1     lukem 				if ( next == mp ) {
    273  1.4  christos 					if ( mc->mc_e == pmp->mp_last ) {
    274  1.4  christos 						pmp->mp_last = prev;
    275  1.4  christos 					}
    276  1.1     lukem 					*entryp = next->mp_next;
    277  1.1     lukem 					entryp = NULL;
    278  1.1     lukem 					break;
    279  1.1     lukem 				}
    280  1.1     lukem 
    281  1.4  christos 				if ( prev != NULL ) {
    282  1.4  christos 					monitor_cache_release( mi, prev );
    283  1.4  christos 				}
    284  1.4  christos 				prev = *entryp;
    285  1.1     lukem 				entryp = &next->mp_next;
    286  1.1     lukem 			}
    287  1.4  christos 			if ( prev ) {
    288  1.4  christos 				monitor_cache_release( mi, prev );
    289  1.4  christos 			}
    290  1.1     lukem 
    291  1.1     lukem 			if ( entryp != NULL ) {
    292  1.1     lukem 				Debug( LDAP_DEBUG_ANY,
    293  1.1     lukem 					"monitor_cache_remove(\"%s\"): "
    294  1.1     lukem 					"not in parent's list\n",
    295  1.3  christos 					ndn->bv_val );
    296  1.1     lukem 			}
    297  1.1     lukem 
    298  1.1     lukem 			/* either succeeded, and the entry is no longer
    299  1.1     lukem 			 * in its parent's list, or failed, and the
    300  1.1     lukem 			 * entry is neither mucked with nor returned */
    301  1.1     lukem 			monitor_cache_release( mi, pmc->mc_e );
    302  1.1     lukem 
    303  1.1     lukem 			if ( entryp == NULL ) {
    304  1.1     lukem 				monitor_cache_t *tmpmc;
    305  1.1     lukem 
    306  1.1     lukem 				tmp_mc.mc_ndn = *ndn;
    307  1.3  christos 				tmpmc = ldap_avl_delete( &mi->mi_cache,
    308  1.1     lukem 					( caddr_t )&tmp_mc, monitor_cache_cmp );
    309  1.1     lukem 				assert( tmpmc == mc );
    310  1.1     lukem 
    311  1.1     lukem 				*ep = mc->mc_e;
    312  1.1     lukem 				ch_free( mc );
    313  1.1     lukem 				mc = NULL;
    314  1.1     lukem 
    315  1.1     lukem 				/* NOTE: we destroy the mutex, but otherwise
    316  1.1     lukem 				 * leave the private data around; specifically,
    317  1.1     lukem 				 * callbacks need be freed by someone else */
    318  1.1     lukem 
    319  1.1     lukem 				ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
    320  1.1     lukem 				mp->mp_next = NULL;
    321  1.1     lukem 				mp->mp_children = NULL;
    322  1.4  christos 				mp->mp_last = NULL;
    323  1.1     lukem 			}
    324  1.1     lukem 
    325  1.1     lukem 		}
    326  1.1     lukem 
    327  1.1     lukem 		if ( mc ) {
    328  1.1     lukem 			monitor_cache_release( mi, mc->mc_e );
    329  1.1     lukem 		}
    330  1.1     lukem 	}
    331  1.1     lukem 
    332  1.4  christos 	ldap_pvt_thread_mutex_unlock( &mi->mi_cache_lock );
    333  1.1     lukem 
    334  1.1     lukem 	return ( *ep == NULL ? -1 : 0 );
    335  1.1     lukem }
    336  1.1     lukem 
    337  1.1     lukem /*
    338  1.1     lukem  * If the entry exists in cache, it is returned in locked status;
    339  1.1     lukem  * otherwise, if the parent exists, if it may generate volatile
    340  1.1     lukem  * descendants an attempt to generate the required entry is
    341  1.1     lukem  * performed and, if successful, the entry is returned
    342  1.1     lukem  */
    343  1.1     lukem int
    344  1.1     lukem monitor_cache_dn2entry(
    345  1.1     lukem 	Operation		*op,
    346  1.1     lukem 	SlapReply		*rs,
    347  1.1     lukem 	struct berval		*ndn,
    348  1.1     lukem 	Entry			**ep,
    349  1.1     lukem 	Entry			**matched )
    350  1.1     lukem {
    351  1.1     lukem 	monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private;
    352  1.1     lukem 	int 			rc;
    353  1.1     lukem 	struct berval		p_ndn = BER_BVNULL;
    354  1.1     lukem 	Entry 			*e_parent;
    355  1.1     lukem 	monitor_entry_t 	*mp;
    356  1.1     lukem 
    357  1.1     lukem 	assert( mi != NULL );
    358  1.1     lukem 	assert( ndn != NULL );
    359  1.1     lukem 	assert( ep != NULL );
    360  1.1     lukem 	assert( matched != NULL );
    361  1.1     lukem 
    362  1.1     lukem 	*matched = NULL;
    363  1.1     lukem 
    364  1.1     lukem 	if ( !dnIsSuffix( ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) {
    365  1.1     lukem 		return( -1 );
    366  1.1     lukem 	}
    367  1.1     lukem 
    368  1.1     lukem 	rc = monitor_cache_get( mi, ndn, ep );
    369  1.1     lukem        	if ( !rc && *ep != NULL ) {
    370  1.1     lukem 		return( 0 );
    371  1.1     lukem 	}
    372  1.1     lukem 
    373  1.1     lukem 	/* try with parent/ancestors */
    374  1.1     lukem 	if ( BER_BVISNULL( ndn ) ) {
    375  1.1     lukem 		BER_BVSTR( &p_ndn, "" );
    376  1.1     lukem 
    377  1.1     lukem 	} else {
    378  1.1     lukem 		dnParent( ndn, &p_ndn );
    379  1.1     lukem 	}
    380  1.1     lukem 
    381  1.1     lukem 	rc = monitor_cache_dn2entry( op, rs, &p_ndn, &e_parent, matched );
    382  1.1     lukem 	if ( rc || e_parent == NULL ) {
    383  1.1     lukem 		return( -1 );
    384  1.1     lukem 	}
    385  1.1     lukem 
    386  1.1     lukem 	mp = ( monitor_entry_t * )e_parent->e_private;
    387  1.1     lukem 	rc = -1;
    388  1.1     lukem 	if ( mp->mp_flags & MONITOR_F_VOLATILE_CH ) {
    389  1.1     lukem 		/* parent entry generates volatile children */
    390  1.1     lukem 		rc = monitor_entry_create( op, rs, ndn, e_parent, ep );
    391  1.1     lukem 	}
    392  1.1     lukem 
    393  1.1     lukem 	if ( !rc ) {
    394  1.1     lukem 		monitor_cache_lock( *ep );
    395  1.1     lukem 		monitor_cache_release( mi, e_parent );
    396  1.1     lukem 
    397  1.1     lukem 	} else {
    398  1.1     lukem 		*matched = e_parent;
    399  1.1     lukem 	}
    400  1.1     lukem 
    401  1.1     lukem 	return( rc );
    402  1.1     lukem }
    403  1.1     lukem 
    404  1.1     lukem /*
    405  1.1     lukem  * releases the lock of the entry; if it is marked as volatile, it is
    406  1.1     lukem  * destroyed.
    407  1.1     lukem  */
    408  1.1     lukem int
    409  1.1     lukem monitor_cache_release(
    410  1.1     lukem 	monitor_info_t	*mi,
    411  1.1     lukem 	Entry		*e )
    412  1.1     lukem {
    413  1.1     lukem 	monitor_entry_t *mp;
    414  1.1     lukem 
    415  1.1     lukem 	assert( mi != NULL );
    416  1.1     lukem 	assert( e != NULL );
    417  1.1     lukem 	assert( e->e_private != NULL );
    418  1.1     lukem 
    419  1.1     lukem 	mp = ( monitor_entry_t * )e->e_private;
    420  1.1     lukem 
    421  1.1     lukem 	if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
    422  1.1     lukem 		ldap_pvt_thread_mutex_unlock( &mp->mp_mutex );
    423  1.1     lukem 		ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
    424  1.1     lukem 		ch_free( mp );
    425  1.1     lukem 		e->e_private = NULL;
    426  1.1     lukem 		entry_free( e );
    427  1.1     lukem 
    428  1.1     lukem 		return( 0 );
    429  1.1     lukem 	}
    430  1.1     lukem 
    431  1.1     lukem 	ldap_pvt_thread_mutex_unlock( &mp->mp_mutex );
    432  1.1     lukem 
    433  1.1     lukem 	return( 0 );
    434  1.1     lukem }
    435  1.1     lukem 
    436  1.1     lukem static void
    437  1.1     lukem monitor_entry_destroy( void *v_mc )
    438  1.1     lukem {
    439  1.1     lukem 	monitor_cache_t		*mc = (monitor_cache_t *)v_mc;
    440  1.1     lukem 
    441  1.1     lukem 	if ( mc->mc_e != NULL ) {
    442  1.1     lukem 		monitor_entry_t *mp;
    443  1.1     lukem 
    444  1.1     lukem 		assert( mc->mc_e->e_private != NULL );
    445  1.1     lukem 
    446  1.1     lukem 		mp = ( monitor_entry_t * )mc->mc_e->e_private;
    447  1.1     lukem 
    448  1.1     lukem 		if ( mp->mp_cb ) {
    449  1.1     lukem 			monitor_callback_t	*cb;
    450  1.1     lukem 
    451  1.1     lukem 			for ( cb = mp->mp_cb; cb != NULL; ) {
    452  1.1     lukem 				monitor_callback_t	*next = cb->mc_next;
    453  1.1     lukem 
    454  1.1     lukem 				if ( cb->mc_free ) {
    455  1.1     lukem 					(void)cb->mc_free( mc->mc_e, &cb->mc_private );
    456  1.1     lukem 				}
    457  1.1     lukem 				ch_free( mp->mp_cb );
    458  1.1     lukem 
    459  1.1     lukem 				cb = next;
    460  1.1     lukem 			}
    461  1.1     lukem 		}
    462  1.1     lukem 
    463  1.1     lukem 		ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
    464  1.1     lukem 
    465  1.1     lukem 		ch_free( mp );
    466  1.1     lukem 		mc->mc_e->e_private = NULL;
    467  1.1     lukem 		entry_free( mc->mc_e );
    468  1.1     lukem 	}
    469  1.1     lukem 
    470  1.1     lukem 	ch_free( mc );
    471  1.1     lukem }
    472  1.1     lukem 
    473  1.1     lukem int
    474  1.1     lukem monitor_cache_destroy(
    475  1.1     lukem 	monitor_info_t	*mi )
    476  1.1     lukem {
    477  1.1     lukem 	if ( mi->mi_cache ) {
    478  1.3  christos 		ldap_avl_free( mi->mi_cache, monitor_entry_destroy );
    479  1.1     lukem 	}
    480  1.1     lukem 
    481  1.1     lukem 	return 0;
    482  1.1     lukem }
    483  1.1     lukem 
    484  1.2  christos int monitor_back_release(
    485  1.2  christos 	Operation *op,
    486  1.2  christos 	Entry *e,
    487  1.2  christos 	int rw )
    488  1.2  christos {
    489  1.2  christos 	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
    490  1.2  christos 	return monitor_cache_release( mi, e );
    491  1.2  christos }
    492