]> git.sur5r.net Git - openldap/blob - servers/slapd/back-monitor/cache.c
address ITS#4332; might remove dynamicObject counting
[openldap] / servers / slapd / back-monitor / cache.c
1 /* cache.c - routines to maintain an in-core cache of entries */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2001-2006 The OpenLDAP Foundation.
6  * Portions Copyright 2001-2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include "ac/string.h"
26
27 #include "slap.h"
28
29 #include "back-monitor.h"
30
31 /*
32  * The cache maps DNs to Entries.
33  * Each entry, on turn, holds the list of its children in the e_private field.
34  * This is used by search operation to perform onelevel and subtree candidate
35  * selection.
36  */
37 typedef struct monitor_cache_t {
38         struct berval           mc_ndn;
39         Entry                   *mc_e;
40 } monitor_cache_t;
41
42 /*
43  * compares entries based on the dn
44  */
45 int
46 monitor_cache_cmp(
47         const void      *c1,
48         const void      *c2 )
49 {
50         monitor_cache_t         *cc1 = ( monitor_cache_t * )c1;
51         monitor_cache_t         *cc2 = ( monitor_cache_t * )c2;
52
53         /*
54          * case sensitive, because the dn MUST be normalized
55          */
56         return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn );
57 }
58
59 /*
60  * checks for duplicate entries
61  */
62 int
63 monitor_cache_dup(
64         void            *c1,
65         void            *c2 )
66 {
67         monitor_cache_t *cc1 = ( monitor_cache_t * )c1;
68         monitor_cache_t *cc2 = ( monitor_cache_t * )c2;
69
70         /*
71          * case sensitive, because the dn MUST be normalized
72          */
73         return ber_bvcmp( &cc1->mc_ndn, &cc2->mc_ndn ) == 0 ? -1 : 0;
74 }
75
76 /*
77  * adds an entry to the cache and inits the mutex
78  */
79 int
80 monitor_cache_add(
81         monitor_info_t  *mi,
82         Entry           *e )
83 {
84         monitor_cache_t *mc;
85         monitor_entry_t *mp;
86         int             rc;
87
88         assert( mi != NULL );
89         assert( e != NULL );
90
91         mp = ( monitor_entry_t *)e->e_private;
92         ldap_pvt_thread_mutex_init( &mp->mp_mutex );
93
94         mc = ( monitor_cache_t * )ch_malloc( sizeof( monitor_cache_t ) );
95         mc->mc_ndn = e->e_nname;
96         mc->mc_e = e;
97         ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
98         rc = avl_insert( &mi->mi_cache, ( caddr_t )mc,
99                         monitor_cache_cmp, monitor_cache_dup );
100         ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
101
102         return rc;
103 }
104
105 /*
106  * locks the entry (no r/w)
107  */
108 int
109 monitor_cache_lock(
110         Entry           *e )
111 {
112         monitor_entry_t *mp;
113
114         assert( e != NULL );
115         assert( e->e_private != NULL );
116
117         mp = ( monitor_entry_t * )e->e_private;
118         ldap_pvt_thread_mutex_lock( &mp->mp_mutex );
119
120         return( 0 );
121 }
122
123 /*
124  * gets an entry from the cache based on the normalized dn 
125  * with mutex locked
126  */
127 int
128 monitor_cache_get(
129         monitor_info_t  *mi,
130         struct berval   *ndn,
131         Entry           **ep )
132 {
133         monitor_cache_t tmp_mc, *mc;
134
135         assert( mi != NULL );
136         assert( ndn != NULL );
137         assert( ep != NULL );
138
139         *ep = NULL;
140
141         tmp_mc.mc_ndn = *ndn;
142         ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
143         mc = ( monitor_cache_t * )avl_find( mi->mi_cache,
144                         ( caddr_t )&tmp_mc, monitor_cache_cmp );
145
146         if ( mc != NULL ) {
147                 /* entry is returned with mutex locked */
148                 monitor_cache_lock( mc->mc_e );
149                 *ep = mc->mc_e;
150         }
151
152         ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
153
154         return ( *ep == NULL ? -1 : 0 );
155 }
156
157 /*
158  * If the entry exists in cache, it is returned in locked status;
159  * otherwise, if the parent exists, if it may generate volatile 
160  * descendants an attempt to generate the required entry is
161  * performed and, if successful, the entry is returned
162  */
163 int
164 monitor_cache_dn2entry(
165         Operation               *op,
166         SlapReply               *rs,
167         struct berval           *ndn,
168         Entry                   **ep,
169         Entry                   **matched )
170 {
171         monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private;
172         int                     rc;
173         struct berval           p_ndn = BER_BVNULL;
174         Entry                   *e_parent;
175         monitor_entry_t         *mp;
176                 
177         assert( mi != NULL );
178         assert( ndn != NULL );
179         assert( ep != NULL );
180         assert( matched != NULL );
181
182         *matched = NULL;
183
184         if ( !dnIsSuffix( ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) {
185                 return( -1 );
186         }
187
188         rc = monitor_cache_get( mi, ndn, ep );
189         if ( !rc && *ep != NULL ) {
190                 return( 0 );
191         }
192
193         /* try with parent/ancestors */
194         if ( BER_BVISNULL( ndn ) ) {
195                 BER_BVSTR( &p_ndn, "" );
196
197         } else {
198                 dnParent( ndn, &p_ndn );
199         }
200
201         rc = monitor_cache_dn2entry( op, rs, &p_ndn, &e_parent, matched );
202         if ( rc || e_parent == NULL ) {
203                 return( -1 );
204         }
205
206         mp = ( monitor_entry_t * )e_parent->e_private;
207         rc = -1;
208         if ( mp->mp_flags & MONITOR_F_VOLATILE_CH ) {
209                 /* parent entry generates volatile children */
210                 rc = monitor_entry_create( op, rs, ndn, e_parent, ep );
211         }
212
213         if ( !rc ) {
214                 monitor_cache_lock( *ep );
215                 monitor_cache_release( mi, e_parent );
216
217         } else {
218                 *matched = e_parent;
219         }
220         
221         return( rc );
222 }
223
224 /*
225  * releases the lock of the entry; if it is marked as volatile, it is
226  * destroyed.
227  */
228 int
229 monitor_cache_release(
230         monitor_info_t  *mi,
231         Entry           *e )
232 {
233         monitor_entry_t *mp;
234
235         assert( mi != NULL );
236         assert( e != NULL );
237         assert( e->e_private != NULL );
238         
239         mp = ( monitor_entry_t * )e->e_private;
240
241         if ( mp->mp_flags & MONITOR_F_VOLATILE ) {
242                 monitor_cache_t *mc, tmp_mc;
243
244                 /* volatile entries do not return to cache */
245                 ldap_pvt_thread_mutex_lock( &mi->mi_cache_mutex );
246                 tmp_mc.mc_ndn = e->e_nname;
247                 mc = avl_delete( &mi->mi_cache,
248                                 ( caddr_t )&tmp_mc, monitor_cache_cmp );
249                 ldap_pvt_thread_mutex_unlock( &mi->mi_cache_mutex );
250                 if ( mc != NULL ) {
251                         ch_free( mc );
252                 }
253                 
254                 ldap_pvt_thread_mutex_unlock( &mp->mp_mutex );
255                 ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
256                 ch_free( mp );
257                 e->e_private = NULL;
258                 entry_free( e );
259
260                 return( 0 );
261         }
262         
263         ldap_pvt_thread_mutex_unlock( &mp->mp_mutex );
264
265         return( 0 );
266 }
267
268 static void
269 monitor_entry_destroy( void *v_mc )
270 {
271         monitor_cache_t         *mc = (monitor_cache_t *)v_mc;
272
273         if ( mc->mc_e != NULL ) {
274                 monitor_entry_t *mp;
275
276                 assert( mc->mc_e->e_private != NULL );
277         
278                 mp = ( monitor_entry_t * )mc->mc_e->e_private;
279
280                 if ( mp->mp_cb ) {
281                         if ( mp->mp_cb->mc_free ) {
282                                 mp->mp_cb->mc_free( mc->mc_e,
283                                         mp->mp_cb->mc_private );
284                         }
285                         ch_free( mp->mp_cb );
286                 }
287
288                 ldap_pvt_thread_mutex_destroy( &mp->mp_mutex );
289
290                 ch_free( mp );
291                 mc->mc_e->e_private = NULL;
292                 entry_free( mc->mc_e );
293         }
294
295         ch_free( mc );
296 }
297
298 int
299 monitor_cache_destroy(
300         monitor_info_t  *mi )
301 {
302         if ( mi->mi_cache ) {
303                 avl_free( mi->mi_cache, monitor_entry_destroy );
304         }
305
306         return 0;
307 }
308