1 /* cache.c - routines to maintain an in-core cache of entries */
4 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
13 #include <ac/string.h>
14 #include <ac/socket.h>
18 #include "back-ldbm.h"
20 /* LDBM backend specific entry info -- visible only to the cache */
21 typedef struct ldbm_entry_info {
22 ldap_pvt_thread_rdwr_t lei_rdwr; /* reader/writer lock */
25 * remaining fields require backend cache lock to access
26 * These items are specific to the LDBM backend and should
29 int lei_state; /* for the cache */
30 #define CACHE_ENTRY_UNDEFINED 0
31 #define CACHE_ENTRY_CREATING 1
32 #define CACHE_ENTRY_READY 2
33 #define CACHE_ENTRY_DELETED 3
35 int lei_refcnt; /* # threads ref'ing this entry */
36 Entry *lei_lrunext; /* for cache lru list */
40 #define LEI(e) ((EntryInfo *) ((e)->e_private))
42 static int cache_delete_entry_internal(Cache *cache, Entry *e);
44 static void lru_print(Cache *cache);
48 cache_entry_rdwr_lock(Entry *e, int rw)
50 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n",
51 rw ? "w" : "r", e->e_id, 0);
54 return ldap_pvt_thread_rdwr_wlock(&LEI(e)->lei_rdwr);
56 return ldap_pvt_thread_rdwr_rlock(&LEI(e)->lei_rdwr);
60 cache_entry_rdwr_trylock(Entry *e, int rw)
62 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%strylock: ID: %ld\n",
63 rw ? "w" : "r", e->e_id, 0);
66 return ldap_pvt_thread_rdwr_wtrylock(&LEI(e)->lei_rdwr);
68 return ldap_pvt_thread_rdwr_rtrylock(&LEI(e)->lei_rdwr);
72 cache_entry_rdwr_unlock(Entry *e, int rw)
74 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%sunlock: ID: %ld\n",
75 rw ? "w" : "r", e->e_id, 0);
78 return ldap_pvt_thread_rdwr_wunlock(&LEI(e)->lei_rdwr);
80 return ldap_pvt_thread_rdwr_runlock(&LEI(e)->lei_rdwr);
84 cache_entry_rdwr_init(Entry *e)
86 return ldap_pvt_thread_rdwr_init( &LEI(e)->lei_rdwr );
90 cache_entry_rdwr_destroy(Entry *e)
92 return ldap_pvt_thread_rdwr_destroy( &LEI(e)->lei_rdwr );
96 cache_entry_private_init( Entry*e )
98 assert( e->e_private == NULL );
100 if( e->e_private != NULL ) {
101 /* this should never happen */
105 e->e_private = ch_calloc(1, sizeof(struct ldbm_entry_info));
107 if( cache_entry_rdwr_init( e ) != 0 ) {
117 cache_entry_private_destroy( Entry*e )
119 assert( e->e_private );
121 cache_entry_rdwr_destroy( e );
123 free( e->e_private );
129 cache_return_entry_rw( Cache *cache, Entry *e, int rw )
134 /* set cache mutex */
135 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
137 assert( e->e_private );
139 cache_entry_rdwr_unlock(e, rw);
142 refcnt = --LEI(e)->lei_refcnt;
144 if ( LEI(e)->lei_state == CACHE_ENTRY_CREATING ) {
145 LEI(e)->lei_state = CACHE_ENTRY_READY;
147 /* free cache mutex */
148 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
150 Debug( LDAP_DEBUG_TRACE,
151 "====> cache_return_entry_%s( %ld ): created (%d)\n",
152 rw ? "w" : "r", id, refcnt );
154 } else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED ) {
156 /* free cache mutex */
157 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
159 Debug( LDAP_DEBUG_TRACE,
160 "====> cache_return_entry_%s( %ld ): delete pending (%d)\n",
161 rw ? "w" : "r", id, refcnt );
164 cache_entry_private_destroy( e );
167 /* free cache mutex */
168 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
170 Debug( LDAP_DEBUG_TRACE,
171 "====> cache_return_entry_%s( %ld ): deleted (%d)\n",
172 rw ? "w" : "r", id, refcnt );
176 /* free cache mutex */
177 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
179 Debug( LDAP_DEBUG_TRACE,
180 "====> cache_return_entry_%s( %ld ): returned (%d)\n",
181 rw ? "w" : "r", id, refcnt);
185 #define LRU_DELETE( cache, e ) do { \
186 if ( LEI(e)->lei_lruprev != NULL ) { \
187 LEI(LEI(e)->lei_lruprev)->lei_lrunext = LEI(e)->lei_lrunext; \
189 (cache)->c_lruhead = LEI(e)->lei_lrunext; \
191 if ( LEI(e)->lei_lrunext != NULL ) { \
192 LEI(LEI(e)->lei_lrunext)->lei_lruprev = LEI(e)->lei_lruprev; \
194 (cache)->c_lrutail = LEI(e)->lei_lruprev; \
198 #define LRU_ADD( cache, e ) do { \
199 LEI(e)->lei_lrunext = (cache)->c_lruhead; \
200 if ( LEI(e)->lei_lrunext != NULL ) { \
201 LEI(LEI(e)->lei_lrunext)->lei_lruprev = (e); \
203 (cache)->c_lruhead = (e); \
204 LEI(e)->lei_lruprev = NULL; \
205 if ( (cache)->c_lrutail == NULL ) { \
206 (cache)->c_lrutail = (e); \
211 * cache_add_entry_rw - create and lock an entry in the cache
212 * returns: 0 entry has been created and locked
213 * 1 entry already existed
214 * -1 something bad happened
226 /* set cache mutex */
227 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
229 assert( e->e_private == NULL );
231 if( cache_entry_private_init(e) != 0 ) {
232 /* free cache mutex */
233 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
235 Debug( LDAP_DEBUG_ANY,
236 "====> cache_add_entry( %ld ): \"%s\": private init failed!\n",
237 e->e_id, e->e_dn, 0 );
242 if ( avl_insert( &cache->c_dntree, (caddr_t) e,
243 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
245 /* free cache mutex */
246 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
248 Debug( LDAP_DEBUG_TRACE,
249 "====> cache_add_entry( %ld ): \"%s\": already in dn cache\n",
250 e->e_id, e->e_dn, 0 );
252 cache_entry_private_destroy(e);
258 if ( avl_insert( &cache->c_idtree, (caddr_t) e,
259 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
261 Debug( LDAP_DEBUG_ANY,
262 "====> cache_add_entry( %ld ): \"%s\": already in id cache\n",
263 e->e_id, e->e_dn, 0 );
266 /* delete from dn tree inserted above */
267 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
268 (AVL_CMP) entry_dn_cmp ) == NULL )
270 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
274 cache_entry_private_destroy(e);
276 /* free cache mutex */
277 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
281 cache_entry_rdwr_lock( e, rw );
283 /* put the entry into 'CREATING' state */
284 /* will be marked after when entry is returned */
285 LEI(e)->lei_state = CACHE_ENTRY_CREATING;
286 LEI(e)->lei_refcnt = 1;
290 if ( ++cache->c_cursize > cache->c_maxsize ) {
292 * find the lru entry not currently in use and delete it.
293 * in case a lot of entries are in use, only look at the
294 * first 10 on the tail of the list.
297 while ( cache->c_lrutail != NULL &&
298 LEI(cache->c_lrutail)->lei_refcnt != 0 &&
301 /* move this in-use entry to the front of the q */
302 ee = cache->c_lrutail;
303 LRU_DELETE( cache, ee );
304 LRU_ADD( cache, ee );
309 * found at least one to delete - try to get back under
310 * the max cache size.
312 while ( cache->c_lrutail != NULL &&
313 LEI(cache->c_lrutail)->lei_refcnt == 0 &&
314 cache->c_cursize > cache->c_maxsize )
316 e = cache->c_lrutail;
318 /* delete from cache and lru q */
319 /* XXX do we need rc ? */
320 rc = cache_delete_entry_internal( cache, e );
321 cache_entry_private_destroy( e );
326 /* free cache mutex */
327 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
332 * cache_update_entry - update a LOCKED entry which has been deleted.
333 * returns: 0 entry has been created and locked
334 * 1 entry already existed
335 * -1 something bad happened
346 /* set cache mutex */
347 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
349 assert( e->e_private );
351 if ( avl_insert( &cache->c_dntree, (caddr_t) e,
352 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
354 Debug( LDAP_DEBUG_TRACE,
355 "====> cache_update_entry( %ld ): \"%s\": already in dn cache\n",
356 e->e_id, e->e_dn, 0 );
358 /* free cache mutex */
359 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
364 if ( avl_insert( &cache->c_idtree, (caddr_t) e,
365 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
367 Debug( LDAP_DEBUG_ANY,
368 "====> cache_update_entry( %ld ): \"%s\": already in id cache\n",
369 e->e_id, e->e_dn, 0 );
371 /* delete from dn tree inserted above */
372 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
373 (AVL_CMP) entry_dn_cmp ) == NULL )
375 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
379 /* free cache mutex */
380 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
385 /* put the entry into 'CREATING' state */
386 /* will be marked after when entry is returned */
387 LEI(e)->lei_state = CACHE_ENTRY_CREATING;
391 if ( ++cache->c_cursize > cache->c_maxsize ) {
393 * find the lru entry not currently in use and delete it.
394 * in case a lot of entries are in use, only look at the
395 * first 10 on the tail of the list.
398 while ( cache->c_lrutail != NULL &&
399 LEI(cache->c_lrutail)->lei_refcnt != 0 &&
402 /* move this in-use entry to the front of the q */
403 ee = cache->c_lrutail;
404 LRU_DELETE( cache, ee );
405 LRU_ADD( cache, ee );
410 * found at least one to delete - try to get back under
411 * the max cache size.
413 while ( cache->c_lrutail != NULL &&
414 LEI(cache->c_lrutail)->lei_refcnt == 0 &&
415 cache->c_cursize > cache->c_maxsize )
417 e = cache->c_lrutail;
419 /* delete from cache and lru q */
420 /* XXX do we need rc ? */
421 rc = cache_delete_entry_internal( cache, e );
422 cache_entry_private_destroy( e );
427 /* free cache mutex */
428 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
433 * cache_find_entry_dn2id - find an entry in the cache, given dn
437 cache_find_entry_dn2id(
447 e.e_dn = (char *) dn;
448 e.e_ndn = ch_strdup( dn );
449 (void) dn_normalize( e.e_ndn );
452 /* set cache mutex */
453 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
455 if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
456 (AVL_CMP) entry_dn_cmp )) != NULL )
462 * ep now points to an unlocked entry
463 * we do not need to lock the entry if we only
464 * check the state, refcnt, LRU, and id.
467 assert( ep->e_private );
471 state = LEI(ep)->lei_state;
474 * entry is deleted or not fully created yet
476 if ( state != CACHE_ENTRY_READY ) {
477 assert(state != CACHE_ENTRY_UNDEFINED);
479 /* free cache mutex */
480 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
482 Debug(LDAP_DEBUG_TRACE,
483 "====> cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
486 ldap_pvt_thread_yield();
491 LRU_DELETE( cache, ep );
492 LRU_ADD( cache, ep );
494 /* free cache mutex */
495 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
497 Debug(LDAP_DEBUG_TRACE,
498 "====> cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
502 /* free cache mutex */
503 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
514 * cache_find_entry_id - find an entry in the cache, given id
531 /* set cache mutex */
532 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
534 if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
535 (AVL_CMP) entry_id_cmp )) != NULL )
542 assert( ep->e_private );
545 state = LEI(ep)->lei_state;
548 * entry is deleted or not fully created yet
550 if ( state != CACHE_ENTRY_READY ) {
552 assert(state != CACHE_ENTRY_UNDEFINED);
554 /* free cache mutex */
555 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
557 Debug(LDAP_DEBUG_TRACE,
558 "====> cache_find_entry_id( %ld ): %ld (not ready) %d\n",
561 ldap_pvt_thread_yield();
565 /* acquire reader lock */
566 if ( cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
567 /* could not acquire entry lock...
568 * owner cannot free as we have the cache locked.
569 * so, unlock the cache, yield, and try again.
572 /* free cache mutex */
573 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
575 Debug(LDAP_DEBUG_TRACE,
576 "====> cache_find_entry_id( %ld ): %ld (busy) %d\n",
579 ldap_pvt_thread_yield();
584 LRU_DELETE( cache, ep );
585 LRU_ADD( cache, ep );
587 LEI(ep)->lei_refcnt++;
589 /* free cache mutex */
590 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
592 Debug(LDAP_DEBUG_TRACE,
593 "====> cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
594 ep_id, ep->e_dn, count);
599 /* free cache mutex */
600 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
606 * cache_delete_entry - delete the entry e from the cache. the caller
607 * should have obtained e (increasing its ref count) via a call to one
608 * of the cache_find_* routines. the caller should *not* call the
609 * cache_return_entry() routine prior to calling cache_delete_entry().
610 * it performs this function.
612 * returns: 0 e was deleted ok
613 * 1 e was not in the cache
614 * -1 something bad happened
624 /* set cache mutex */
625 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
627 assert( e->e_private );
629 Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry( %ld )\n",
632 rc = cache_delete_entry_internal( cache, e );
634 /* free cache mutex */
635 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
640 cache_delete_entry_internal(
645 int rc = 0; /* return code */
648 if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
655 if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
666 LRU_DELETE( cache, e );
670 * flag entry to be freed later by a call to cache_return_entry()
672 LEI(e)->lei_state = CACHE_ENTRY_DELETED;
678 cache_release_all( Cache *cache )
683 /* set cache mutex */
684 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
686 Debug( LDAP_DEBUG_TRACE, "====> cache_release_all\n", 0, 0, 0 );
688 while ( (e = cache->c_lrutail) != NULL && LEI(e)->lei_refcnt == 0 ) {
689 #ifdef LDAP_RDWR_DEBUG
690 assert(!ldap_pvt_thread_rdwr_active(&LEI(e)->lei_rdwr));
693 /* delete from cache and lru q */
694 /* XXX do we need rc ? */
695 rc = cache_delete_entry_internal( cache, e );
696 cache_entry_private_destroy( e );
700 if ( cache->c_cursize ) {
701 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
704 /* free cache mutex */
705 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
711 lru_print( Cache *cache )
715 fprintf( stderr, "LRU queue (head to tail):\n" );
716 for ( e = cache->c_lruhead; e != NULL; e = LEI(e)->lei_lrunext ) {
717 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
718 e->e_dn, e->e_id, LEI(e)->lei_refcnt );
720 fprintf( stderr, "LRU queue (tail to head):\n" );
721 for ( e = cache->c_lrutail; e != NULL; e = LEI(e)->lei_lruprev ) {
722 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
723 e->e_dn, e->e_id, LEI(e)->lei_refcnt );