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