X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-monitor%2Fcache.c;h=2d9fd751877d14a4516377de5a267bdf9550995a;hb=f980c64cb63abca0928e176a9443d8513b74ef74;hp=d1455a182063a960fb35ffb1003d5f9da5afaccd;hpb=6939c531700652491f4be4688c6a1f35a1ab8a18;p=openldap diff --git a/servers/slapd/back-monitor/cache.c b/servers/slapd/back-monitor/cache.c index d1455a1820..10ed890719 100644 --- a/servers/slapd/back-monitor/cache.c +++ b/servers/slapd/back-monitor/cache.c @@ -1,55 +1,54 @@ /* cache.c - routines to maintain an in-core cache of entries */ -/* - * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * 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 + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ -/* - * 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. +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion + * in OpenLDAP Software. */ #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 @@ -62,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 @@ -80,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 ); @@ -110,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 ); } /* @@ -130,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 ); } /* @@ -169,17 +288,17 @@ monitor_cache_get( */ int monitor_cache_dn2entry( - struct monitorinfo *mi, - struct berval *ndn, - Entry **ep, - Entry **matched -) + Operation *op, + SlapReply *rs, + struct berval *ndn, + Entry **ep, + Entry **matched ) { - int rc; - - struct berval p_ndn = { 0L, NULL }; + monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private; + int rc; + struct berval p_ndn = BER_BVNULL; Entry *e_parent; - struct monitorentrypriv *mp; + monitor_entry_t *mp; assert( mi != NULL ); assert( ndn != NULL ); @@ -188,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( mi, &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( mi, 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; } @@ -234,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 ); @@ -255,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 ); @@ -271,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 ); +}