X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-monitor%2Fcache.c;h=10ed890719e3fa3ceb0587b36b7536d6a66833b0;hb=f980c64cb63abca0928e176a9443d8513b74ef74;hp=f818f70aa321fc66a2bc28f5a9a64d7597a16137;hpb=0bc23d571e8ab5b42032a0abccb31fbd4714bc7c;p=openldap diff --git a/servers/slapd/back-monitor/cache.c b/servers/slapd/back-monitor/cache.c index f818f70aa3..10ed890719 100644 --- a/servers/slapd/back-monitor/cache.c +++ b/servers/slapd/back-monitor/cache.c @@ -2,7 +2,8 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2003 The OpenLDAP Foundation. + * Copyright 2001-2012 The OpenLDAP Foundation. + * Portions Copyright 2001-2003 Pierangelo Masarati. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -17,54 +18,37 @@ * This work was initially developed by Pierangelo Masarati for inclusion * in OpenLDAP Software. */ -/* This is an altered version */ -/* - * Copyright 2001, Pierangelo Masarati, All rights reserved. - * - * This work has beed deveolped for the OpenLDAP Foundation - * in the hope that it may be useful to the Open Source community, - * but WITHOUT ANY WARRANTY. - * - * Permission is granted to anyone to use this software for any purpose - * on any computer system, and to alter it and redistribute it, subject - * to the following restrictions: - * - * 1. The author and SysNet s.n.c. are not responsible for the consequences - * of use of this software, no matter how awful, even if they arise from - * flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits should appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits should appear in the documentation. - * SysNet s.n.c. cannot be responsible for the consequences of the - * alterations. - * - * 4. This notice may not be removed or altered. - */ #include "portable.h" #include +#include "ac/string.h" #include "slap.h" #include "back-monitor.h" +/* + * The cache maps DNs to Entries. + * Each entry, on turn, holds the list of its children in the e_private field. + * This is used by search operation to perform onelevel and subtree candidate + * selection. + */ +typedef struct monitor_cache_t { + struct berval mc_ndn; + Entry *mc_e; +} monitor_cache_t; + /* * compares entries based on the dn */ int monitor_cache_cmp( - const void *c1, - const void *c2 -) + const void *c1, + const void *c2 ) { - struct monitorcache *cc1 = ( struct monitorcache * )c1; - struct monitorcache *cc2 = ( struct monitorcache * )c2; + monitor_cache_t *cc1 = ( monitor_cache_t * )c1; + monitor_cache_t *cc2 = ( monitor_cache_t * )c2; /* * case sensitive, because the dn MUST be normalized @@ -77,12 +61,11 @@ monitor_cache_cmp( */ int monitor_cache_dup( - void *c1, - void *c2 -) + void *c1, + void *c2 ) { - struct monitorcache *cc1 = ( struct monitorcache * )c1; - struct monitorcache *cc2 = ( struct monitorcache * )c2; + monitor_cache_t *cc1 = ( monitor_cache_t * )c1; + monitor_cache_t *cc2 = ( monitor_cache_t * )c2; /* * case sensitive, because the dn MUST be normalized @@ -95,21 +78,19 @@ monitor_cache_dup( */ int monitor_cache_add( - struct monitorinfo *mi, - Entry *e -) + monitor_info_t *mi, + Entry *e ) { - struct monitorcache *mc; - struct monitorentrypriv *mp; - int rc; + monitor_cache_t *mc; + monitor_entry_t *mp; + int rc; assert( mi != NULL ); assert( e != NULL ); - mp = ( struct monitorentrypriv *)e->e_private; - ldap_pvt_thread_mutex_init( &mp->mp_mutex ); + mp = ( monitor_entry_t *)e->e_private; - mc = ( struct monitorcache * )ch_malloc( sizeof( struct monitorcache ) ); + mc = ( monitor_cache_t * )ch_malloc( sizeof( monitor_cache_t ) ); mc->mc_ndn = e->e_nname; mc->mc_e = e; ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); @@ -125,18 +106,33 @@ monitor_cache_add( */ int monitor_cache_lock( - Entry *e -) + Entry *e ) { - struct monitorentrypriv *mp; + monitor_entry_t *mp; - assert( e != NULL ); - assert( e->e_private != NULL ); + assert( e != NULL ); + assert( e->e_private != NULL ); - mp = ( struct monitorentrypriv * )e->e_private; - ldap_pvt_thread_mutex_lock( &mp->mp_mutex ); + mp = ( monitor_entry_t * )e->e_private; + ldap_pvt_thread_mutex_lock( &mp->mp_mutex ); - return( 0 ); + return( 0 ); +} + +/* + * tries to lock the entry (no r/w) + */ +int +monitor_cache_trylock( + Entry *e ) +{ + monitor_entry_t *mp; + + assert( e != NULL ); + assert( e->e_private != NULL ); + + mp = ( monitor_entry_t * )e->e_private; + return ldap_pvt_thread_mutex_trylock( &mp->mp_mutex ); } /* @@ -145,35 +141,143 @@ monitor_cache_lock( */ int monitor_cache_get( - struct monitorinfo *mi, - struct berval *ndn, - Entry **ep -) + monitor_info_t *mi, + struct berval *ndn, + Entry **ep ) { - struct monitorcache tmp_mc, *mc; + monitor_cache_t tmp_mc, *mc; assert( mi != NULL ); assert( ndn != NULL ); assert( ep != NULL ); + *ep = NULL; + tmp_mc.mc_ndn = *ndn; +retry:; ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); - mc = ( struct monitorcache * )avl_find( mi->mi_cache, + mc = ( monitor_cache_t * )avl_find( mi->mi_cache, ( caddr_t )&tmp_mc, monitor_cache_cmp ); if ( mc != NULL ) { /* entry is returned with mutex locked */ - monitor_cache_lock( mc->mc_e ); - ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + if ( monitor_cache_trylock( mc->mc_e ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + ldap_pvt_thread_yield(); + goto retry; + } *ep = mc->mc_e; - - return( 0 ); } - + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + + return ( *ep == NULL ? -1 : 0 ); +} + +/* + * gets an entry from the cache based on the normalized dn + * with mutex locked + */ +int +monitor_cache_remove( + monitor_info_t *mi, + struct berval *ndn, + Entry **ep ) +{ + monitor_cache_t tmp_mc, *mc; + struct berval pndn; + + assert( mi != NULL ); + assert( ndn != NULL ); + assert( ep != NULL ); + *ep = NULL; - return( -1 ); + dnParent( ndn, &pndn ); + +retry:; + ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); + + tmp_mc.mc_ndn = *ndn; + mc = ( monitor_cache_t * )avl_find( mi->mi_cache, + ( caddr_t )&tmp_mc, monitor_cache_cmp ); + + if ( mc != NULL ) { + monitor_cache_t *pmc; + + if ( monitor_cache_trylock( mc->mc_e ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + goto retry; + } + + tmp_mc.mc_ndn = pndn; + pmc = ( monitor_cache_t * )avl_find( mi->mi_cache, + ( caddr_t )&tmp_mc, monitor_cache_cmp ); + if ( pmc != NULL ) { + monitor_entry_t *mp = (monitor_entry_t *)mc->mc_e->e_private, + *pmp = (monitor_entry_t *)pmc->mc_e->e_private; + Entry **entryp; + + if ( monitor_cache_trylock( pmc->mc_e ) ) { + monitor_cache_release( mi, mc->mc_e ); + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + goto retry; + } + + for ( entryp = &pmp->mp_children; *entryp != NULL; ) { + monitor_entry_t *next = (monitor_entry_t *)(*entryp)->e_private; + if ( next == mp ) { + *entryp = next->mp_next; + entryp = NULL; + break; + } + + entryp = &next->mp_next; + } + + if ( entryp != NULL ) { + Debug( LDAP_DEBUG_ANY, + "monitor_cache_remove(\"%s\"): " + "not in parent's list\n", + ndn->bv_val, 0, 0 ); + } + + /* either succeeded, and the entry is no longer + * in its parent's list, or failed, and the + * entry is neither mucked with nor returned */ + monitor_cache_release( mi, pmc->mc_e ); + + if ( entryp == NULL ) { + monitor_cache_t *tmpmc; + + tmp_mc.mc_ndn = *ndn; + tmpmc = avl_delete( &mi->mi_cache, + ( caddr_t )&tmp_mc, monitor_cache_cmp ); + assert( tmpmc == mc ); + + *ep = mc->mc_e; + ch_free( mc ); + mc = NULL; + + /* NOTE: we destroy the mutex, but otherwise + * leave the private data around; specifically, + * callbacks need be freed by someone else */ + + ldap_pvt_thread_mutex_destroy( &mp->mp_mutex ); + mp->mp_next = NULL; + mp->mp_children = NULL; + } + + } + + if ( mc ) { + monitor_cache_release( mi, mc->mc_e ); + } + } + + ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); + + return ( *ep == NULL ? -1 : 0 ); } /* @@ -184,17 +288,17 @@ monitor_cache_get( */ int monitor_cache_dn2entry( - Operation *op, - struct berval *ndn, - Entry **ep, - Entry **matched -) + Operation *op, + SlapReply *rs, + struct berval *ndn, + Entry **ep, + Entry **matched ) { - struct monitorinfo *mi = (struct monitorinfo *)op->o_bd->be_private; + monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private; int rc; - struct berval p_ndn = { 0L, NULL }; + struct berval p_ndn = BER_BVNULL; Entry *e_parent; - struct monitorentrypriv *mp; + monitor_entry_t *mp; assert( mi != NULL ); assert( ndn != NULL ); @@ -203,39 +307,39 @@ monitor_cache_dn2entry( *matched = NULL; + if ( !dnIsSuffix( ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) { + return( -1 ); + } + rc = monitor_cache_get( mi, ndn, ep ); if ( !rc && *ep != NULL ) { return( 0 ); } /* try with parent/ancestors */ - if ( ndn->bv_len ) { - dnParent( ndn, &p_ndn ); - } + if ( BER_BVISNULL( ndn ) ) { + BER_BVSTR( &p_ndn, "" ); - if ( p_ndn.bv_val == NULL ) { - p_ndn.bv_val = ""; - p_ndn.bv_len = 0; - } else { - p_ndn.bv_len = ndn->bv_len - - ( ber_len_t ) ( p_ndn.bv_val - ndn->bv_val ); + dnParent( ndn, &p_ndn ); } - rc = monitor_cache_dn2entry( op, &p_ndn, &e_parent, matched ); - if ( rc || e_parent == NULL) { + rc = monitor_cache_dn2entry( op, rs, &p_ndn, &e_parent, matched ); + if ( rc || e_parent == NULL ) { return( -1 ); } - mp = ( struct monitorentrypriv * )e_parent->e_private; + mp = ( monitor_entry_t * )e_parent->e_private; rc = -1; if ( mp->mp_flags & MONITOR_F_VOLATILE_CH ) { /* parent entry generates volatile children */ - rc = monitor_entry_create( op, ndn, e_parent, ep ); + rc = monitor_entry_create( op, rs, ndn, e_parent, ep ); } if ( !rc ) { + monitor_cache_lock( *ep ); monitor_cache_release( mi, e_parent ); + } else { *matched = e_parent; } @@ -249,20 +353,19 @@ monitor_cache_dn2entry( */ int monitor_cache_release( - struct monitorinfo *mi, - Entry *e -) + monitor_info_t *mi, + Entry *e ) { - struct monitorentrypriv *mp; + monitor_entry_t *mp; assert( mi != NULL ); assert( e != NULL ); assert( e->e_private != NULL ); - mp = ( struct monitorentrypriv * )e->e_private; + mp = ( monitor_entry_t * )e->e_private; if ( mp->mp_flags & MONITOR_F_VOLATILE ) { - struct monitorcache *mc, tmp_mc; + monitor_cache_t *mc, tmp_mc; /* volatile entries do not return to cache */ ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex ); @@ -270,7 +373,9 @@ monitor_cache_release( mc = avl_delete( &mi->mi_cache, ( caddr_t )&tmp_mc, monitor_cache_cmp ); ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex ); - ch_free( mc ); + if ( mc != NULL ) { + ch_free( mc ); + } ldap_pvt_thread_mutex_unlock( &mp->mp_mutex ); ldap_pvt_thread_mutex_destroy( &mp->mp_mutex ); @@ -286,3 +391,59 @@ monitor_cache_release( return( 0 ); } +static void +monitor_entry_destroy( void *v_mc ) +{ + monitor_cache_t *mc = (monitor_cache_t *)v_mc; + + if ( mc->mc_e != NULL ) { + monitor_entry_t *mp; + + assert( mc->mc_e->e_private != NULL ); + + mp = ( monitor_entry_t * )mc->mc_e->e_private; + + if ( mp->mp_cb ) { + monitor_callback_t *cb; + + for ( cb = mp->mp_cb; cb != NULL; ) { + monitor_callback_t *next = cb->mc_next; + + if ( cb->mc_free ) { + (void)cb->mc_free( mc->mc_e, &cb->mc_private ); + } + ch_free( mp->mp_cb ); + + cb = next; + } + } + + ldap_pvt_thread_mutex_destroy( &mp->mp_mutex ); + + ch_free( mp ); + mc->mc_e->e_private = NULL; + entry_free( mc->mc_e ); + } + + ch_free( mc ); +} + +int +monitor_cache_destroy( + monitor_info_t *mi ) +{ + if ( mi->mi_cache ) { + avl_free( mi->mi_cache, monitor_entry_destroy ); + } + + return 0; +} + +int monitor_back_release( + Operation *op, + Entry *e, + int rw ) +{ + monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; + return monitor_cache_release( mi, e ); +}