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>
20 /* BDB backend specific entry info -- visible only to the cache */
21 typedef struct bdb_entry_info {
22 ldap_pvt_thread_rdwr_t bei_rdwr; /* reader/writer lock */
25 * remaining fields require backend cache lock to access
26 * These items are specific to the BDB backend and should
29 int bei_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
34 #define CACHE_ENTRY_COMMITTED 4
36 int bei_refcnt; /* # threads ref'ing this entry */
37 Entry *bei_lrunext; /* for cache lru list */
41 #define BEI(e) ((EntryInfo *) ((e)->e_private))
43 static int bdb_cache_delete_entry_internal(Cache *cache, Entry *e);
45 static void bdb_lru_print(Cache *cache);
49 bdb_cache_entry_rdwr_lock(Entry *e, int rw)
52 LDAP_LOG( CACHE, ENTRY,
53 "bdb_cache_entry_rdwr_lock: %s lock on ID %ld\n",
54 rw ? "w" : "r", e->e_id, 0 );
56 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n",
57 rw ? "w" : "r", e->e_id, 0);
61 return ldap_pvt_thread_rdwr_wlock(&BEI(e)->bei_rdwr);
63 return ldap_pvt_thread_rdwr_rlock(&BEI(e)->bei_rdwr);
67 bdb_cache_entry_rdwr_trylock(Entry *e, int rw)
70 LDAP_LOG( CACHE, ENTRY,
71 "bdb_cache_entry_rdwr_trylock: try %s lock on ID: %ld.\n",
72 rw ? "w" : "r", e->e_id, 0 );
74 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%strylock: ID: %ld\n",
75 rw ? "w" : "r", e->e_id, 0);
79 return ldap_pvt_thread_rdwr_wtrylock(&BEI(e)->bei_rdwr);
81 return ldap_pvt_thread_rdwr_rtrylock(&BEI(e)->bei_rdwr);
85 bdb_cache_entry_rdwr_unlock(Entry *e, int rw)
88 LDAP_LOG( CACHE, ENTRY,
89 "bdb_cache_entry_rdwr_unlock: remove %s lock on ID %ld.\n",
90 rw ? "w" : "r", e->e_id, 0 );
92 Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%sunlock: ID: %ld\n",
93 rw ? "w" : "r", e->e_id, 0);
97 return ldap_pvt_thread_rdwr_wunlock(&BEI(e)->bei_rdwr);
99 return ldap_pvt_thread_rdwr_runlock(&BEI(e)->bei_rdwr);
103 bdb_cache_entry_rdwr_init(Entry *e)
105 return ldap_pvt_thread_rdwr_init( &BEI(e)->bei_rdwr );
109 bdb_cache_entry_rdwr_destroy(Entry *e)
111 return ldap_pvt_thread_rdwr_destroy( &BEI(e)->bei_rdwr );
115 bdb_cache_entry_private_init( Entry *e )
117 assert( e->e_private == NULL );
119 if( e->e_private != NULL ) {
120 /* this should never happen */
124 e->e_private = ch_calloc(1, sizeof(struct bdb_entry_info));
126 if( bdb_cache_entry_rdwr_init( e ) != 0 ) {
136 bdb_cache_entry_db_lock
137 ( DB_ENV *env, u_int32_t locker, Entry *e, int rw, u_int32_t flags, DB_LOCK *lock )
144 db_rw = DB_LOCK_WRITE;
146 db_rw = DB_LOCK_READ;
148 lockobj.data = e->e_nname.bv_val;
149 lockobj.size = e->e_nname.bv_len;
150 rc = LOCK_GET(env, locker, flags | DB_LOCK_NOWAIT,
151 &lockobj, db_rw, lock);
154 LDAP_LOG( CACHE, DETAIL1,
155 "bdb_cache_entry_db_lock: entry %s, rw %d, rc %d\n",
156 e->e_nname.bv_val, rw, rc );
158 Debug( LDAP_DEBUG_TRACE,
159 "bdb_cache_entry_db_lock: entry %s, rw %d, rc %d\n",
160 e->e_nname.bv_val, rw, rc );
167 bdb_cache_entry_db_unlock
168 ( DB_ENV *env, DB_LOCK *lock )
172 rc = LOCK_PUT ( env, lock );
177 * marks an entry in CREATING state as committed, so it is really returned
178 * to the cache. Otherwise an entry in CREATING state is removed.
179 * Makes e_private be destroyed at the following cache_return_entry_w,
180 * but lets the entry untouched (owned by someone else)
183 bdb_cache_entry_commit( Entry *e )
186 assert( e->e_private );
187 assert( BEI(e)->bei_state == CACHE_ENTRY_CREATING );
188 /* assert( BEI(e)->bei_refcnt == 1 ); */
190 BEI(e)->bei_state = CACHE_ENTRY_COMMITTED;
194 bdb_cache_entry_private_destroy( Entry *e )
196 assert( e->e_private );
198 bdb_cache_entry_rdwr_destroy( e );
200 free( e->e_private );
206 bdb_unlocked_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
210 int refcnt, freeit = 1;
212 /* set cache write lock */
213 ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
215 assert( e->e_private );
218 bdb_cache_entry_rdwr_unlock(e, rw);
222 refcnt = --BEI(e)->bei_refcnt;
225 * if the entry is returned when in CREATING state, it is deleted
226 * but not freed because it may belong to someone else (do_add,
229 if ( BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
231 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
232 bdb_cache_delete_entry_internal( cache, e );
234 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
236 /* now the entry is in DELETED state */
239 if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
240 BEI(e)->bei_state = CACHE_ENTRY_READY;
242 /* free cache write lock */
243 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
246 LDAP_LOG( CACHE, DETAIL1,
247 "bdb_unlocked_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
248 id, rw ? "w" : "r", refcnt );
250 Debug( LDAP_DEBUG_TRACE,
251 "====> bdb_unlocked_cache_return_entry_%s( %ld ): created (%d)\n",
252 rw ? "w" : "r", id, refcnt );
256 } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
258 /* free cache write lock */
259 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
262 LDAP_LOG( CACHE, DETAIL1,
263 "bdb_unlocked_cache_return_entry_rw: %ld, delete pending (%d).\n",
266 Debug( LDAP_DEBUG_TRACE,
267 "====> bdb_unlocked_cache_return_entry_%s( %ld ): delete pending (%d)\n",
268 rw ? "w" : "r", id, refcnt );
272 bdb_cache_entry_private_destroy( e );
274 bdb_entry_return( e );
277 /* free cache write lock */
278 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
281 LDAP_LOG( CACHE, DETAIL1,
282 "bdb_unlocked_cache_return_entry_rw: (%ld): deleted (%d)\n",
285 Debug( LDAP_DEBUG_TRACE,
286 "====> bdb_unlocked_cache_return_entry_%s( %ld ): deleted (%d)\n",
287 rw ? "w" : "r", id, refcnt );
292 /* free cache write lock */
293 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
296 LDAP_LOG( CACHE, DETAIL1,
297 "bdb_unlocked_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
298 id, rw ? "w": "r", refcnt );
300 Debug( LDAP_DEBUG_TRACE,
301 "====> bdb_unlocked_cache_return_entry_%s( %ld ): returned (%d)\n",
302 rw ? "w" : "r", id, refcnt);
308 bdb_cache_return_entry_rw
309 ( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock )
312 int refcnt, freeit = 1;
314 /* set cache write lock */
315 ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
317 assert( e->e_private );
319 bdb_cache_entry_db_unlock( env, lock );
321 bdb_cache_entry_rdwr_unlock(e, rw);
325 refcnt = --BEI(e)->bei_refcnt;
328 * if the entry is returned when in CREATING state, it is deleted
329 * but not freed because it may belong to someone else (do_add,
332 if ( BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
334 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
335 bdb_cache_delete_entry_internal( cache, e );
337 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
339 /* now the entry is in DELETED state */
342 if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
343 BEI(e)->bei_state = CACHE_ENTRY_READY;
345 /* free cache write lock */
346 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
349 LDAP_LOG( CACHE, DETAIL1,
350 "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
351 id, rw ? "w" : "r", refcnt );
353 Debug( LDAP_DEBUG_TRACE,
354 "====> bdb_cache_return_entry_%s( %ld ): created (%d)\n",
355 rw ? "w" : "r", id, refcnt );
359 } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
361 /* free cache write lock */
362 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
365 LDAP_LOG( CACHE, DETAIL1,
366 "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n",
369 Debug( LDAP_DEBUG_TRACE,
370 "====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n",
371 rw ? "w" : "r", id, refcnt );
375 bdb_cache_entry_private_destroy( e );
377 bdb_entry_return( e );
380 /* free cache write lock */
381 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
384 LDAP_LOG( CACHE, DETAIL1,
385 "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n",
388 Debug( LDAP_DEBUG_TRACE,
389 "====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n",
390 rw ? "w" : "r", id, refcnt );
395 /* free cache write lock */
396 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
399 LDAP_LOG( CACHE, DETAIL1,
400 "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
401 id, rw ? "w": "r", refcnt );
403 Debug( LDAP_DEBUG_TRACE,
404 "====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n",
405 rw ? "w" : "r", id, refcnt);
410 #define LRU_DELETE( cache, e ) do { \
411 if ( BEI(e)->bei_lruprev != NULL ) { \
412 BEI(BEI(e)->bei_lruprev)->bei_lrunext = BEI(e)->bei_lrunext; \
414 (cache)->c_lruhead = BEI(e)->bei_lrunext; \
416 if ( BEI(e)->bei_lrunext != NULL ) { \
417 BEI(BEI(e)->bei_lrunext)->bei_lruprev = BEI(e)->bei_lruprev; \
419 (cache)->c_lrutail = BEI(e)->bei_lruprev; \
423 #define LRU_ADD( cache, e ) do { \
424 BEI(e)->bei_lrunext = (cache)->c_lruhead; \
425 if ( BEI(e)->bei_lrunext != NULL ) { \
426 BEI(BEI(e)->bei_lrunext)->bei_lruprev = (e); \
428 (cache)->c_lruhead = (e); \
429 BEI(e)->bei_lruprev = NULL; \
430 if ( (cache)->c_lrutail == NULL ) { \
431 (cache)->c_lrutail = (e); \
436 * cache_add_entry_rw - create and lock an entry in the cache
437 * returns: 0 entry has been created and locked
438 * 1 entry already existed
439 * -1 something bad happened
440 * other Berkeley DB locking error code
443 bdb_cache_add_entry_rw(
456 LDAP_LOG( CACHE, ENTRY,
457 "bdb_cache_add_entry_rw: add (%s):%s to cache\n",
458 e->e_dn, rw ? "w" : "r", 0 );
460 /* set cache write lock */
461 ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
463 assert( e->e_private == NULL );
465 if( bdb_cache_entry_private_init(e) != 0 ) {
466 /* free cache write lock */
467 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
470 LDAP_LOG( CACHE, ERR,
471 "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n",
472 e->e_dn, e->e_id, 0 );
474 Debug( LDAP_DEBUG_ANY,
475 "====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n",
476 e->e_id, e->e_dn, 0 );
483 if ( avl_insert( &cache->c_dntree, (caddr_t) e,
484 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
486 /* free cache write lock */
487 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
490 LDAP_LOG( CACHE, DETAIL1,
491 "bdb_cache_add_entry: (%s):%ld already in cache.\n",
492 e->e_dn, e->e_id, 0 );
494 Debug( LDAP_DEBUG_TRACE,
495 "====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n",
496 e->e_id, e->e_dn, 0 );
499 bdb_cache_entry_private_destroy(e);
505 if ( avl_insert( &cache->c_idtree, (caddr_t) e,
506 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
509 LDAP_LOG( CACHE, DETAIL1,
510 "bdb_cache_add_entry: (%s):%ls already in cache.\n",
511 e->e_dn, e->e_id, 0 );
513 Debug( LDAP_DEBUG_ANY,
514 "====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n",
515 e->e_id, e->e_dn, 0 );
518 /* delete from dn tree inserted above */
519 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
520 (AVL_CMP) entry_dn_cmp ) == NULL )
523 LDAP_LOG( CACHE, INFO,
524 "bdb_cache_add_entry: can't delete (%s) from cache.\n",
527 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
532 bdb_cache_entry_private_destroy(e);
534 /* free cache write lock */
535 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
539 rc = bdb_cache_entry_db_lock( env, locker, e, rw, 0, lock );
543 case DB_LOCK_DEADLOCK :
544 case DB_LOCK_NOTGRANTED :
545 /* undo avl changes immediately */
546 if ( avl_delete( &cache->c_idtree, (caddr_t) e,
547 (AVL_CMP) entry_id_cmp ) == NULL ) {
549 LDAP_LOG( CACHE, INFO,
550 "bdb_cache_add_entry: can't delete (%s) from cache.\n",
553 Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 );
556 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
557 (AVL_CMP) entry_dn_cmp ) == NULL ) {
559 LDAP_LOG( CACHE, INFO,
560 "bdb_cache_add_entry: can't delete (%s) from cache.\n",
563 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 );
568 bdb_cache_entry_private_destroy(e);
569 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
573 /* put the entry into 'CREATING' state */
574 /* will be marked after when entry is returned */
575 BEI(e)->bei_state = CACHE_ENTRY_CREATING;
576 BEI(e)->bei_refcnt = 1;
579 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
582 if ( ++cache->c_cursize > cache->c_maxsize ) {
584 * find the lru entry not currently in use and delete it.
585 * in case a lot of entries are in use, only look at the
586 * first 10 on the tail of the list.
589 while ( cache->c_lrutail != NULL &&
590 BEI(cache->c_lrutail)->bei_refcnt != 0 &&
593 /* move this in-use entry to the front of the q */
594 ee = cache->c_lrutail;
595 LRU_DELETE( cache, ee );
596 LRU_ADD( cache, ee );
601 * found at least one to delete - try to get back under
602 * the max cache size.
604 while ( cache->c_lrutail != NULL &&
605 BEI(cache->c_lrutail)->bei_refcnt == 0 &&
606 cache->c_cursize > cache->c_maxsize )
608 e = cache->c_lrutail;
610 /* delete from cache and lru q */
611 /* XXX do we need rc ? */
612 rc = bdb_cache_delete_entry_internal( cache, e );
613 bdb_cache_entry_private_destroy( e );
614 bdb_entry_return( e );
619 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
620 /* free cache write lock */
621 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
626 * cache_update_entry - update a LOCKED entry which has been deleted.
627 * returns: 0 entry has been created and locked
628 * 1 entry already existed
629 * -1 something bad happened
632 bdb_cache_update_entry(
640 /* set cache write lock */
641 ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
643 assert( e->e_private );
645 if ( avl_insert( &cache->c_dntree, (caddr_t) e,
646 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
649 LDAP_LOG( CACHE, DETAIL1,
650 "bdb_cache_update_entry: (%s):%ld already in dn cache\n",
651 e->e_dn, e->e_id, 0 );
653 Debug( LDAP_DEBUG_TRACE,
654 "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n",
655 e->e_id, e->e_dn, 0 );
658 /* free cache write lock */
659 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
664 if ( avl_insert( &cache->c_idtree, (caddr_t) e,
665 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
668 LDAP_LOG( CACHE, DETAIL1,
669 "bdb_cache_update_entry: (%s)%ld already in id cache\n",
670 e->e_dn, e->e_id, 0 );
672 Debug( LDAP_DEBUG_ANY,
673 "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n",
674 e->e_id, e->e_dn, 0 );
677 /* delete from dn tree inserted above */
678 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
679 (AVL_CMP) entry_dn_cmp ) == NULL )
682 LDAP_LOG( CACHE, INFO,
683 "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n",
684 e->e_dn, e->e_id, 0 );
686 Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
691 /* free cache write lock */
692 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
697 /* put the entry into 'CREATING' state */
698 /* will be marked after when entry is returned */
699 BEI(e)->bei_state = CACHE_ENTRY_CREATING;
702 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
705 if ( ++cache->c_cursize > cache->c_maxsize ) {
707 * find the lru entry not currently in use and delete it.
708 * in case a lot of entries are in use, only look at the
709 * first 10 on the tail of the list.
712 while ( cache->c_lrutail != NULL &&
713 BEI(cache->c_lrutail)->bei_refcnt != 0 &&
716 /* move this in-use entry to the front of the q */
717 ee = cache->c_lrutail;
718 LRU_DELETE( cache, ee );
719 LRU_ADD( cache, ee );
724 * found at least one to delete - try to get back under
725 * the max cache size.
727 while ( cache->c_lrutail != NULL &&
728 BEI(cache->c_lrutail)->bei_refcnt == 0 &&
729 cache->c_cursize > cache->c_maxsize )
731 e = cache->c_lrutail;
733 /* delete from cache and lru q */
734 /* XXX do we need rc ? */
735 rc = bdb_cache_delete_entry_internal( cache, e );
736 bdb_cache_entry_private_destroy( e );
737 bdb_entry_return( e );
742 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
743 /* free cache write lock */
744 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
749 bdb_cache_find_entry_ndn2id(
759 /* this function is always called with normalized DN */
763 /* set cache read lock */
764 ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
766 if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
767 (AVL_CMP) entry_dn_cmp )) != NULL )
773 * ep now points to an unlocked entry
774 * we do not need to lock the entry if we only
775 * check the state, refcnt, LRU, and id.
778 assert( ep->e_private );
782 state = BEI(ep)->bei_state;
785 * entry is deleted or not fully created yet
787 if ( state != CACHE_ENTRY_READY ) {
788 assert(state != CACHE_ENTRY_UNDEFINED);
790 /* free cache read lock */
791 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
794 LDAP_LOG( CACHE, INFO,
795 "bdb_cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
796 ndn->bv_val, id, state );
798 Debug(LDAP_DEBUG_TRACE,
799 "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
800 ndn->bv_val, id, state);
804 ldap_pvt_thread_yield();
808 /* free cache read lock */
809 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
812 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
815 LRU_DELETE( cache, ep );
816 LRU_ADD( cache, ep );
819 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
822 LDAP_LOG( CACHE, DETAIL1,
823 "bdb_cache_find_entry_dn2id: (%s): %ld %d tries\n",
824 ndn->bv_val, id, count );
826 Debug(LDAP_DEBUG_TRACE,
827 "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
828 ndn->bv_val, id, count);
832 /* free cache read lock */
833 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
842 * cache_find_entry_id - find an entry in the cache, given id
846 bdb_cache_find_entry_id(
863 /* set cache read lock */
864 ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
866 if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
867 (AVL_CMP) entry_id_cmp )) != NULL )
874 assert( ep->e_private );
877 state = BEI(ep)->bei_state;
880 * entry is deleted or not fully created yet
882 if ( state != CACHE_ENTRY_READY ) {
884 assert(state != CACHE_ENTRY_UNDEFINED);
886 /* free cache read lock */
887 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
890 LDAP_LOG( CACHE, INFO,
891 "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
895 Debug(LDAP_DEBUG_TRACE,
896 "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n",
900 ldap_pvt_thread_yield();
904 /* acquire reader lock */
905 rc = bdb_cache_entry_db_lock ( env, locker, ep, rw, 0, lock );
908 if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
911 if ( rc ) { /* will be changed to retry beyond threshold */
912 /* could not acquire entry lock...
913 * owner cannot free as we have the cache locked.
914 * so, unlock the cache, yield, and try again.
917 /* free cache read lock */
918 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
921 LDAP_LOG( CACHE, INFO,
922 "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n",
925 Debug(LDAP_DEBUG_TRACE,
926 "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n",
928 Debug(LDAP_DEBUG_TRACE,
933 ldap_pvt_thread_yield();
937 /* free cache read lock */
938 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
940 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
942 LRU_DELETE( cache, ep );
943 LRU_ADD( cache, ep );
945 BEI(ep)->bei_refcnt++;
948 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
951 LDAP_LOG( CACHE, DETAIL1,
952 "bdb_cache_find_entry_id: %ld -> %s found %d tries.\n",
953 ep_id, ep->e_dn, count );
955 Debug(LDAP_DEBUG_TRACE,
956 "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
957 ep_id, ep->e_dn, count);
964 /* free cache read lock */
965 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
971 * cache_delete_entry - delete the entry e from the cache. the caller
972 * should have obtained e (increasing its ref count) via a call to one
973 * of the cache_find_* routines. the caller should *not* call the
974 * cache_return_entry() routine prior to calling cache_delete_entry().
975 * it performs this function.
977 * returns: 0 e was deleted ok
978 * 1 e was not in the cache
979 * -1 something bad happened
982 bdb_cache_delete_entry(
989 /* set cache write lock */
990 ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
992 assert( e->e_private );
995 LDAP_LOG( CACHE, ENTRY,
996 "bdb_cache_delete_entry: delete %ld.\n", e->e_id, 0, 0 );
998 Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n",
1003 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
1004 rc = bdb_cache_delete_entry_internal( cache, e );
1005 /* free lru mutex */
1006 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
1008 /* free cache write lock */
1009 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
1014 bdb_cache_delete_entry_internal(
1019 int rc = 0; /* return code */
1022 if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
1029 if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
1040 LRU_DELETE( cache, e );
1044 * flag entry to be freed later by a call to cache_return_entry()
1046 BEI(e)->bei_state = CACHE_ENTRY_DELETED;
1052 bdb_cache_release_all( Cache *cache )
1057 /* set cache write lock */
1058 ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
1060 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
1063 LDAP_LOG( CACHE, ENTRY, "bdb_cache_release_all: enter\n", 0, 0, 0 );
1065 Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 );
1068 while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) {
1069 #ifdef LDAP_RDWR_DEBUG
1070 assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr));
1073 /* delete from cache and lru q */
1074 /* XXX do we need rc ? */
1075 rc = bdb_cache_delete_entry_internal( cache, e );
1076 bdb_cache_entry_private_destroy( e );
1077 bdb_entry_return( e );
1080 if ( cache->c_cursize ) {
1082 LDAP_LOG( CACHE, INFO,
1083 "bdb_cache_release_all: Entry cache could not be emptied.\n", 0, 0, 0 );
1085 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
1090 /* free lru mutex */
1091 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
1092 /* free cache write lock */
1093 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
1098 bdb_lru_print( Cache *cache )
1102 fprintf( stderr, "LRU queue (head to tail):\n" );
1103 for ( e = cache->c_lruhead; e != NULL; e = BEI(e)->bei_lrunext ) {
1104 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
1105 e->e_dn, e->e_id, BEI(e)->bei_refcnt );
1107 fprintf( stderr, "LRU queue (tail to head):\n" );
1108 for ( e = cache->c_lrutail; e != NULL; e = BEI(e)->bei_lruprev ) {
1109 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
1110 e->e_dn, e->e_id, BEI(e)->bei_refcnt );
1115 #ifdef BDB_REUSE_LOCKERS
1117 bdb_locker_id_free( void *key, void *data )
1120 int lockid = (int) data;
1122 XLOCK_ID_FREE( env, lockid );
1126 bdb_locker_id( Operation *op, DB_ENV *env, int *locker )
1131 if ( !env || !op || !locker ) return -1;
1133 /* Shouldn't happen unless we're single-threaded */
1134 if ( !op->o_threadctx ) {
1139 if ( ldap_pvt_thread_pool_getkey( op->o_threadctx, env, &data, NULL ) ) {
1140 for ( i=0, rc=1; rc != 0 && i<4; i++ ) {
1141 rc = XLOCK_ID( env, &lockid );
1142 if (rc) ldap_pvt_thread_yield();
1147 data = (void *)lockid;
1148 if ( ( rc = ldap_pvt_thread_pool_setkey( op->o_threadctx, env,
1149 data, bdb_locker_id_free ) ) ) {
1150 XLOCK_ID_FREE( env, lockid );
1152 LDAP_LOG( BACK_BDB, ERR, "bdb_locker_id: err %s(%d)\n",
1153 db_strerror(rc), rc, 0 );
1155 Debug( LDAP_DEBUG_ANY, "bdb_locker_id: err %s(%d)\n",
1156 db_strerror(rc), rc, 0 );