1 /* cache.c - routines to maintain an in-core cache of entries */
4 * Copyright 1998-2002 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 #ifdef LDBM_ENTRY_RWLOCK
23 ldap_pvt_thread_rdwr_t lei_rdwr; /* reader/writer lock */
27 * remaining fields require backend cache lock to access
28 * These items are specific to the LDBM backend and should
31 int lei_state; /* for the cache */
32 #define CACHE_ENTRY_UNDEFINED 0
33 #define CACHE_ENTRY_CREATING 1
34 #define CACHE_ENTRY_READY 2
35 #define CACHE_ENTRY_DELETED 3
36 #define CACHE_ENTRY_COMMITTED 4
38 int lei_refcnt; /* # threads ref'ing this entry */
39 Entry *lei_lrunext; /* for cache lru list */
43 #define LEI(e) ((EntryInfo *) ((e)->e_private))
45 static int cache_delete_entry_internal(Cache *cache, Entry *e);
47 static void lru_print(Cache *cache);
50 #ifdef LDBM_ENTRY_RWLOCK
52 cache_entry_rdwr_lock(Entry *e, int rw)
55 LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
56 "cache_entry_rdwr_lock: %s lock on ID %ld\n",
57 rw ? "w" : "r", e->e_id ));
59 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n",
60 rw ? "w" : "r", e->e_id, 0);
65 return ldap_pvt_thread_rdwr_wlock(&LEI(e)->lei_rdwr);
67 return ldap_pvt_thread_rdwr_rlock(&LEI(e)->lei_rdwr);
71 cache_entry_rdwr_trylock(Entry *e, int rw)
74 LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
75 "cache_entry_rdwr_trylock: try %s lock on ID: %ld.\n",
76 rw ? "w" : "r", e->e_id ));
78 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%strylock: ID: %ld\n",
79 rw ? "w" : "r", e->e_id, 0);
84 return ldap_pvt_thread_rdwr_wtrylock(&LEI(e)->lei_rdwr);
86 return ldap_pvt_thread_rdwr_rtrylock(&LEI(e)->lei_rdwr);
90 cache_entry_rdwr_unlock(Entry *e, int rw)
93 LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
94 "cache_entry_rdwr_unlock: remove %s lock on ID %ld.\n",
95 rw ? "w" : "r", e->e_id ));
97 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%sunlock: ID: %ld\n",
98 rw ? "w" : "r", e->e_id, 0);
103 return ldap_pvt_thread_rdwr_wunlock(&LEI(e)->lei_rdwr);
105 return ldap_pvt_thread_rdwr_runlock(&LEI(e)->lei_rdwr);
109 cache_entry_rdwr_init(Entry *e)
111 return ldap_pvt_thread_rdwr_init( &LEI(e)->lei_rdwr );
115 cache_entry_rdwr_destroy(Entry *e)
117 return ldap_pvt_thread_rdwr_destroy( &LEI(e)->lei_rdwr );
122 cache_entry_private_init( Entry*e )
124 assert( e->e_private == NULL );
126 if( e->e_private != NULL ) {
127 /* this should never happen */
131 e->e_private = ch_calloc(1, sizeof(struct ldbm_entry_info));
133 #ifdef LDBM_ENTRY_RWLOCK
134 if( cache_entry_rdwr_init( e ) != 0 ) {
145 * marks an entry in CREATING state as committed, so it is really returned
146 * to the cache. Otherwise an entry in CREATING state is removed.
147 * Makes e_private be destroyed at the following cache_return_entry_w,
148 * but lets the entry untouched (owned by someone else)
151 cache_entry_commit( Entry *e )
154 assert( e->e_private );
155 assert( LEI(e)->lei_state == CACHE_ENTRY_CREATING );
156 /* assert( LEI(e)->lei_refcnt == 1 ); */
158 LEI(e)->lei_state = CACHE_ENTRY_COMMITTED;
162 cache_entry_private_destroy( Entry*e )
164 assert( e->e_private );
166 #ifdef LDBM_ENTRY_RWLOCK
167 cache_entry_rdwr_destroy( e );
170 free( e->e_private );
176 cache_return_entry_rw( Cache *cache, Entry *e, int rw )
179 int refcnt, freeit = 1;
181 /* set cache mutex */
182 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
184 assert( e->e_private );
186 #ifdef LDBM_ENTRY_RWLOCK
187 cache_entry_rdwr_unlock(e, rw);
191 refcnt = --LEI(e)->lei_refcnt;
194 * if the entry is returned when in CREATING state, it is deleted
195 * but not freed because it may belong to someone else (do_add,
198 if ( LEI(e)->lei_state == CACHE_ENTRY_CREATING ) {
199 cache_delete_entry_internal( cache, e );
201 /* now the entry is in DELETED state */
204 if ( LEI(e)->lei_state == CACHE_ENTRY_COMMITTED ) {
205 LEI(e)->lei_state = CACHE_ENTRY_READY;
207 /* free cache mutex */
208 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
211 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
212 "cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
213 id, rw ? "w" : "r", refcnt ));
215 Debug( LDAP_DEBUG_TRACE,
216 "====> cache_return_entry_%s( %ld ): created (%d)\n",
217 rw ? "w" : "r", id, refcnt );
221 } else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED ) {
223 /* free cache mutex */
224 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
227 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
228 "cache_return_entry_rw: %ld, delete pending (%d).\n",
231 Debug( LDAP_DEBUG_TRACE,
232 "====> cache_return_entry_%s( %ld ): delete pending (%d)\n",
233 rw ? "w" : "r", id, refcnt );
238 cache_entry_private_destroy( e );
243 /* free cache mutex */
244 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
247 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
248 "cache_return_entry_rw: (%ld): deleted (%d)\n",
251 Debug( LDAP_DEBUG_TRACE,
252 "====> cache_return_entry_%s( %ld ): deleted (%d)\n",
253 rw ? "w" : "r", id, refcnt );
259 /* free cache mutex */
260 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
263 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
264 "cache_return_entry_rw: ID %ld:%s returned (%d)\n",
265 id, rw ? "w": "r", refcnt ));
267 Debug( LDAP_DEBUG_TRACE,
268 "====> cache_return_entry_%s( %ld ): returned (%d)\n",
269 rw ? "w" : "r", id, refcnt);
275 #define LRU_DELETE( cache, e ) do { \
276 if ( LEI(e)->lei_lruprev != NULL ) { \
277 LEI(LEI(e)->lei_lruprev)->lei_lrunext = LEI(e)->lei_lrunext; \
279 (cache)->c_lruhead = LEI(e)->lei_lrunext; \
281 if ( LEI(e)->lei_lrunext != NULL ) { \
282 LEI(LEI(e)->lei_lrunext)->lei_lruprev = LEI(e)->lei_lruprev; \
284 (cache)->c_lrutail = LEI(e)->lei_lruprev; \
288 #define LRU_ADD( cache, e ) do { \
289 LEI(e)->lei_lrunext = (cache)->c_lruhead; \
290 if ( LEI(e)->lei_lrunext != NULL ) { \
291 LEI(LEI(e)->lei_lrunext)->lei_lruprev = (e); \
293 (cache)->c_lruhead = (e); \
294 LEI(e)->lei_lruprev = NULL; \
295 if ( (cache)->c_lrutail == NULL ) { \
296 (cache)->c_lrutail = (e); \
301 * cache_add_entry_rw - create and lock an entry in the cache
302 * returns: 0 entry has been created and locked
303 * 1 entry already existed
304 * -1 something bad happened
317 LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
318 "cache_add_entry_rw: add (%s):%s to cache\n",
319 e->e_dn, rw ? "w" : "r" ));
321 /* set cache mutex */
322 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
324 assert( e->e_private == NULL );
326 if( cache_entry_private_init(e) != 0 ) {
327 /* free cache mutex */
328 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
331 LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
332 "cache_add_entry_rw: add (%s):%ld private init failed!\n",
335 Debug( LDAP_DEBUG_ANY,
336 "====> cache_add_entry( %ld ): \"%s\": private init failed!\n",
337 e->e_id, e->e_dn, 0 );
344 if ( avl_insert( &cache->c_dntree, (caddr_t) e,
345 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
347 /* free cache mutex */
348 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
351 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
352 "cache_add_entry: (%s):%ld already in cache.\n",
355 Debug( LDAP_DEBUG_TRACE,
356 "====> cache_add_entry( %ld ): \"%s\": already in dn cache\n",
357 e->e_id, e->e_dn, 0 );
361 cache_entry_private_destroy(e);
367 if ( avl_insert( &cache->c_idtree, (caddr_t) e,
368 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
371 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
372 "cache_add_entry: (%s):%ls already in cache.\n",
375 Debug( LDAP_DEBUG_ANY,
376 "====> cache_add_entry( %ld ): \"%s\": already in id cache\n",
377 e->e_id, e->e_dn, 0 );
380 /* delete from dn tree inserted above */
381 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
382 (AVL_CMP) entry_dn_cmp ) == NULL )
385 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
386 "cache_add_entry: can't delete (%s) from cache.\n",
389 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
394 cache_entry_private_destroy(e);
396 /* free cache mutex */
397 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
401 #ifdef LDBM_ENTRY_RWLOCK
402 cache_entry_rdwr_lock( e, rw );
405 /* put the entry into 'CREATING' state */
406 /* will be marked after when entry is returned */
407 LEI(e)->lei_state = CACHE_ENTRY_CREATING;
408 LEI(e)->lei_refcnt = 1;
412 if ( ++cache->c_cursize > cache->c_maxsize ) {
414 * find the lru entry not currently in use and delete it.
415 * in case a lot of entries are in use, only look at the
416 * first 10 on the tail of the list.
419 while ( cache->c_lrutail != NULL &&
420 LEI(cache->c_lrutail)->lei_refcnt != 0 &&
423 /* move this in-use entry to the front of the q */
424 ee = cache->c_lrutail;
425 LRU_DELETE( cache, ee );
426 LRU_ADD( cache, ee );
431 * found at least one to delete - try to get back under
432 * the max cache size.
434 while ( cache->c_lrutail != NULL &&
435 LEI(cache->c_lrutail)->lei_refcnt == 0 &&
436 cache->c_cursize > cache->c_maxsize )
438 e = cache->c_lrutail;
440 /* delete from cache and lru q */
441 /* XXX do we need rc ? */
442 rc = cache_delete_entry_internal( cache, e );
443 cache_entry_private_destroy( e );
448 /* free cache mutex */
449 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
454 * cache_update_entry - update a LOCKED entry which has been deleted.
455 * returns: 0 entry has been created and locked
456 * 1 entry already existed
457 * -1 something bad happened
468 /* set cache mutex */
469 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
471 assert( e->e_private );
473 if ( avl_insert( &cache->c_dntree, (caddr_t) e,
474 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
477 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
478 "cache_update_entry: (%s):%ld already in dn cache\n",
481 Debug( LDAP_DEBUG_TRACE,
482 "====> cache_update_entry( %ld ): \"%s\": already in dn cache\n",
483 e->e_id, e->e_dn, 0 );
487 /* free cache mutex */
488 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
493 if ( avl_insert( &cache->c_idtree, (caddr_t) e,
494 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
497 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
498 "cache_update_entry: (%s)%ld already in id cache\n",
501 Debug( LDAP_DEBUG_ANY,
502 "====> cache_update_entry( %ld ): \"%s\": already in id cache\n",
503 e->e_id, e->e_dn, 0 );
507 /* delete from dn tree inserted above */
508 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
509 (AVL_CMP) entry_dn_cmp ) == NULL )
512 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
513 "cache_update_entry: can't delete (%s)%ld from dn cache.\n",
516 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
522 /* free cache mutex */
523 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
528 /* put the entry into 'CREATING' state */
529 /* will be marked after when entry is returned */
530 LEI(e)->lei_state = CACHE_ENTRY_CREATING;
534 if ( ++cache->c_cursize > cache->c_maxsize ) {
536 * find the lru entry not currently in use and delete it.
537 * in case a lot of entries are in use, only look at the
538 * first 10 on the tail of the list.
541 while ( cache->c_lrutail != NULL &&
542 LEI(cache->c_lrutail)->lei_refcnt != 0 &&
545 /* move this in-use entry to the front of the q */
546 ee = cache->c_lrutail;
547 LRU_DELETE( cache, ee );
548 LRU_ADD( cache, ee );
553 * found at least one to delete - try to get back under
554 * the max cache size.
556 while ( cache->c_lrutail != NULL &&
557 LEI(cache->c_lrutail)->lei_refcnt == 0 &&
558 cache->c_cursize > cache->c_maxsize )
560 e = cache->c_lrutail;
562 /* delete from cache and lru q */
563 /* XXX do we need rc ? */
564 rc = cache_delete_entry_internal( cache, e );
565 cache_entry_private_destroy( e );
570 /* free cache mutex */
571 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
576 cache_find_entry_ndn2id(
586 /* this function is always called with normalized DN */
590 /* set cache mutex */
591 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
593 if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
594 (AVL_CMP) entry_dn_cmp )) != NULL )
600 * ep now points to an unlocked entry
601 * we do not need to lock the entry if we only
602 * check the state, refcnt, LRU, and id.
605 assert( ep->e_private );
609 state = LEI(ep)->lei_state;
612 * entry is deleted or not fully created yet
614 if ( state != CACHE_ENTRY_READY ) {
615 assert(state != CACHE_ENTRY_UNDEFINED);
617 /* free cache mutex */
618 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
621 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
622 "cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
623 ndn->bv_val, id, state ));
625 Debug(LDAP_DEBUG_TRACE,
626 "====> cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
627 ndn->bv_val, id, state);
631 ldap_pvt_thread_yield();
636 LRU_DELETE( cache, ep );
637 LRU_ADD( cache, ep );
639 /* free cache mutex */
640 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
643 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
644 "cache_find_entry_dn2id: (%s): %ld %d tries\n",
645 ndn->bv_val, id, count ));
647 Debug(LDAP_DEBUG_TRACE,
648 "====> cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
649 ndn->bv_val, id, count);
654 /* free cache mutex */
655 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
664 * cache_find_entry_id - find an entry in the cache, given id
681 /* set cache mutex */
682 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
684 if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
685 (AVL_CMP) entry_id_cmp )) != NULL )
692 assert( ep->e_private );
695 state = LEI(ep)->lei_state;
698 * entry is deleted or not fully created yet
700 if ( state != CACHE_ENTRY_READY ) {
702 assert(state != CACHE_ENTRY_UNDEFINED);
704 /* free cache mutex */
705 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
708 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
709 "cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
713 Debug(LDAP_DEBUG_TRACE,
714 "====> cache_find_entry_id( %ld ): %ld (not ready) %d\n",
719 ldap_pvt_thread_yield();
723 #ifdef LDBM_ENTRY_RWLOCK
724 /* acquire reader lock */
725 if ( cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
726 /* could not acquire entry lock...
727 * owner cannot free as we have the cache locked.
728 * so, unlock the cache, yield, and try again.
731 /* free cache mutex */
732 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
735 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
736 "cache_find_entry_id: %ld -> %ld (busy) %d.\n",
739 Debug(LDAP_DEBUG_TRACE,
740 "====> cache_find_entry_id( %ld ): %ld (busy) %d\n",
745 ldap_pvt_thread_yield();
751 LRU_DELETE( cache, ep );
752 LRU_ADD( cache, ep );
754 LEI(ep)->lei_refcnt++;
756 /* free cache mutex */
757 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
760 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
761 "cache_find_entry_id: %ld -> %s found %d tries.\n",
762 ep_id, ep->e_dn, count ));
764 Debug(LDAP_DEBUG_TRACE,
765 "====> cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
766 ep_id, ep->e_dn, count);
773 /* free cache mutex */
774 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
780 * cache_delete_entry - delete the entry e from the cache. the caller
781 * should have obtained e (increasing its ref count) via a call to one
782 * of the cache_find_* routines. the caller should *not* call the
783 * cache_return_entry() routine prior to calling cache_delete_entry().
784 * it performs this function.
786 * returns: 0 e was deleted ok
787 * 1 e was not in the cache
788 * -1 something bad happened
798 /* set cache mutex */
799 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
801 assert( e->e_private );
804 LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
805 "cache_delete_entry: delete %ld.\n", e->e_id ));
807 Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry( %ld )\n",
812 rc = cache_delete_entry_internal( cache, e );
814 /* free cache mutex */
815 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
820 cache_delete_entry_internal(
825 int rc = 0; /* return code */
828 if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
835 if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
846 LRU_DELETE( cache, e );
850 * flag entry to be freed later by a call to cache_return_entry()
852 LEI(e)->lei_state = CACHE_ENTRY_DELETED;
858 cache_release_all( Cache *cache )
863 /* set cache mutex */
864 ldap_pvt_thread_mutex_lock( &cache->c_mutex );
867 LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
868 "cache_release_all: enter\n" ));
870 Debug( LDAP_DEBUG_TRACE, "====> cache_release_all\n", 0, 0, 0 );
874 while ( (e = cache->c_lrutail) != NULL && LEI(e)->lei_refcnt == 0 ) {
875 #ifdef LDAP_RDWR_DEBUG
876 assert(!ldap_pvt_thread_rdwr_active(&LEI(e)->lei_rdwr));
879 /* delete from cache and lru q */
880 /* XXX do we need rc ? */
881 rc = cache_delete_entry_internal( cache, e );
882 cache_entry_private_destroy( e );
886 if ( cache->c_cursize ) {
888 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
889 "cache_release_all: Entry cache could not be emptied.\n" ));
891 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
896 /* free cache mutex */
897 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
903 lru_print( Cache *cache )
907 fprintf( stderr, "LRU queue (head to tail):\n" );
908 for ( e = cache->c_lruhead; e != NULL; e = LEI(e)->lei_lrunext ) {
909 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
910 e->e_dn, e->e_id, LEI(e)->lei_refcnt );
912 fprintf( stderr, "LRU queue (tail to head):\n" );
913 for ( e = cache->c_lrutail; e != NULL; e = LEI(e)->lei_lruprev ) {
914 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
915 e->e_dn, e->e_id, LEI(e)->lei_refcnt );