]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/cache.c
Switch to openldap-data
[openldap] / servers / slapd / back-bdb / cache.c
1 /* cache.c - routines to maintain an in-core cache of entries */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/errno.h>
13 #include <ac/string.h>
14 #include <ac/socket.h>
15
16 #include "slap.h"
17
18 #include "back-bdb.h"
19
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 */
23
24         /*
25          * remaining fields require backend cache lock to access
26          * These items are specific to the LDBM backend and should
27          * be hidden.
28          */
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
35         
36         int             bei_refcnt;     /* # threads ref'ing this entry */
37         Entry   *bei_lrunext;   /* for cache lru list */
38         Entry   *bei_lruprev;
39 } EntryInfo;
40 #undef BEI
41 #define BEI(e)  ((EntryInfo *) ((e)->e_private))
42
43 static int      bdb_cache_delete_entry_internal(Cache *cache, Entry *e);
44 #ifdef LDAP_DEBUG
45 static void     lru_print(Cache *cache);
46 #endif
47
48 static int
49 bdb_cache_entry_rdwr_lock(Entry *e, int rw)
50 {
51 #ifdef NEW_LOGGING
52         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
53                    "bdb_cache_entry_rdwr_lock: %s lock on ID %ld\n",
54                    rw ? "w" : "r", e->e_id ));
55 #else
56         Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n",
57                 rw ? "w" : "r", e->e_id, 0);
58 #endif
59
60         if (rw)
61                 return ldap_pvt_thread_rdwr_wlock(&BEI(e)->bei_rdwr);
62         else
63                 return ldap_pvt_thread_rdwr_rlock(&BEI(e)->bei_rdwr);
64 }
65
66 static int
67 bdb_cache_entry_rdwr_trylock(Entry *e, int rw)
68 {
69 #ifdef NEW_LOGGING
70         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
71                    "bdb_cache_entry_rdwr_trylock: try %s lock on ID: %ld.\n",
72                    rw ? "w" : "r", e->e_id ));
73 #else
74         Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%strylock: ID: %ld\n",
75                 rw ? "w" : "r", e->e_id, 0);
76 #endif
77
78
79         if (rw)
80                 return ldap_pvt_thread_rdwr_wtrylock(&BEI(e)->bei_rdwr);
81         else
82                 return ldap_pvt_thread_rdwr_rtrylock(&BEI(e)->bei_rdwr);
83 }
84
85 static int
86 bdb_cache_entry_rdwr_unlock(Entry *e, int rw)
87 {
88 #ifdef NEW_LOGGING
89         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
90                    "bdb_cache_entry_rdwr_unlock: remove %s lock on ID %ld.\n",
91                    rw ? "w" : "r", e->e_id ));
92 #else
93         Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%sunlock: ID: %ld\n",
94                 rw ? "w" : "r", e->e_id, 0);
95 #endif
96
97
98         if (rw)
99                 return ldap_pvt_thread_rdwr_wunlock(&BEI(e)->bei_rdwr);
100         else
101                 return ldap_pvt_thread_rdwr_runlock(&BEI(e)->bei_rdwr);
102 }
103
104 static int
105 bdb_cache_entry_rdwr_init(Entry *e)
106 {
107         return ldap_pvt_thread_rdwr_init( &BEI(e)->bei_rdwr );
108 }
109
110 static int
111 bdb_cache_entry_rdwr_destroy(Entry *e)
112 {
113         return ldap_pvt_thread_rdwr_destroy( &BEI(e)->bei_rdwr );
114 }
115
116 static int
117 bdb_cache_entry_private_init( Entry *e )
118 {
119         assert( e->e_private == NULL );
120
121         if( e->e_private != NULL ) {
122                 /* this should never happen */
123                 return 1;
124         }
125
126         e->e_private = ch_calloc(1, sizeof(struct bdb_entry_info));
127
128         if( bdb_cache_entry_rdwr_init( e ) != 0 ) {
129                 free( BEI(e) );
130                 e->e_private = NULL;
131                 return 1;
132         } 
133
134         return 0;
135 }
136
137 /*
138  * marks an entry in CREATING state as committed, so it is really returned
139  * to the cache. Otherwise an entry in CREATING state is removed.
140  * Makes e_private be destroyed at the following cache_return_entry_w,
141  * but lets the entry untouched (owned by someone else)
142  */
143 void
144 bdb_cache_entry_commit( Entry *e )
145 {
146         assert( e );
147         assert( e->e_private );
148         assert( BEI(e)->bei_state == CACHE_ENTRY_CREATING );
149         /* assert( BEI(e)->bei_refcnt == 1 ); */
150
151         BEI(e)->bei_state = CACHE_ENTRY_COMMITTED;
152 }
153
154 static int
155 bdb_cache_entry_private_destroy( Entry *e )
156 {
157         assert( e->e_private );
158
159         bdb_cache_entry_rdwr_destroy( e );
160
161         free( e->e_private );
162         e->e_private = NULL;
163         return 0;
164 }
165
166 void
167 bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
168 {
169         ID id;
170         int refcnt, freeit = 1;
171
172         /* set cache mutex */
173         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
174
175         assert( e->e_private );
176
177         bdb_cache_entry_rdwr_unlock(e, rw);
178
179         id = e->e_id;
180         refcnt = --BEI(e)->bei_refcnt;
181
182         /*
183          * if the entry is returned when in CREATING state, it is deleted
184          * but not freed because it may belong to someone else (do_add,
185          * for instance)
186          */
187         if (  BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
188                 bdb_cache_delete_entry_internal( cache, e );
189                 freeit = 0;
190                 /* now the entry is in DELETED state */
191         }
192
193         if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
194                 BEI(e)->bei_state = CACHE_ENTRY_READY;
195
196                 /* free cache mutex */
197                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
198
199 #ifdef NEW_LOGGING
200                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
201                            "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
202                            id, rw ? "w" : "r", refcnt ));
203 #else
204                 Debug( LDAP_DEBUG_TRACE,
205                         "====> bdb_cache_return_entry_%s( %ld ): created (%d)\n",
206                         rw ? "w" : "r", id, refcnt );
207 #endif
208
209
210         } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
211                 if( refcnt > 0 ) {
212                         /* free cache mutex */
213                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
214
215 #ifdef NEW_LOGGING
216                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
217                                    "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n",
218                                    id, refcnt ));
219 #else
220                         Debug( LDAP_DEBUG_TRACE,
221                                 "====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n",
222                                 rw ? "w" : "r", id, refcnt );
223 #endif
224
225
226                 } else {
227                         bdb_cache_entry_private_destroy( e );
228                         if ( freeit ) {
229                                 bdb_entry_return( e );
230                         }
231
232                         /* free cache mutex */
233                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
234
235 #ifdef NEW_LOGGING
236                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
237                                    "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n",
238                                    id, refcnt ));
239 #else
240                         Debug( LDAP_DEBUG_TRACE,
241                                 "====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n",
242                                 rw ? "w" : "r", id, refcnt );
243 #endif
244
245                 }
246
247         } else {
248                 /* free cache mutex */
249                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
250
251 #ifdef NEW_LOGGING
252                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
253                            "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
254                            id, rw ? "w": "r", refcnt ));
255 #else
256                 Debug( LDAP_DEBUG_TRACE,
257                         "====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n",
258                         rw ? "w" : "r", id, refcnt);
259 #endif
260
261         }
262 }
263
264 #define LRU_DELETE( cache, e ) do { \
265         if ( BEI(e)->bei_lruprev != NULL ) { \
266                 BEI(BEI(e)->bei_lruprev)->bei_lrunext = BEI(e)->bei_lrunext; \
267         } else { \
268                 (cache)->c_lruhead = BEI(e)->bei_lrunext; \
269         } \
270         if ( BEI(e)->bei_lrunext != NULL ) { \
271                 BEI(BEI(e)->bei_lrunext)->bei_lruprev = BEI(e)->bei_lruprev; \
272         } else { \
273                 (cache)->c_lrutail = BEI(e)->bei_lruprev; \
274         } \
275 } while(0)
276
277 #define LRU_ADD( cache, e ) do { \
278         BEI(e)->bei_lrunext = (cache)->c_lruhead; \
279         if ( BEI(e)->bei_lrunext != NULL ) { \
280                 BEI(BEI(e)->bei_lrunext)->bei_lruprev = (e); \
281         } \
282         (cache)->c_lruhead = (e); \
283         BEI(e)->bei_lruprev = NULL; \
284         if ( (cache)->c_lrutail == NULL ) { \
285                 (cache)->c_lrutail = (e); \
286         } \
287 } while(0)
288
289 /*
290  * cache_add_entry_rw - create and lock an entry in the cache
291  * returns:     0       entry has been created and locked
292  *              1       entry already existed
293  *              -1      something bad happened
294  */
295 int
296 bdb_cache_add_entry_rw(
297     Cache       *cache,
298     Entry       *e,
299     int         rw
300 )
301 {
302         int     i, rc;
303         Entry   *ee;
304
305 #ifdef NEW_LOGGING
306         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
307                    "bdb_cache_add_entry_rw: add (%s):%s to cache\n",
308                    e->e_dn, rw ? "w" : "r" ));
309 #endif
310         /* set cache mutex */
311         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
312
313         assert( e->e_private == NULL );
314
315         if( bdb_cache_entry_private_init(e) != 0 ) {
316                 /* free cache mutex */
317                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
318
319 #ifdef NEW_LOGGING
320                 LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
321                            "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n",
322                            e->e_dn, e->e_id ));
323 #else
324                 Debug( LDAP_DEBUG_ANY,
325                         "====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n",
326                     e->e_id, e->e_dn, 0 );
327 #endif
328
329
330                 return( -1 );
331         }
332
333         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
334                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
335         {
336                 /* free cache mutex */
337                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
338
339 #ifdef NEW_LOGGING
340                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
341                            "bdb_cache_add_entry: (%s):%ld already in cache.\n",
342                            e->e_dn, e->e_id ));
343 #else
344                 Debug( LDAP_DEBUG_TRACE,
345                         "====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n",
346                     e->e_id, e->e_dn, 0 );
347 #endif
348
349
350                 bdb_cache_entry_private_destroy(e);
351
352                 return( 1 );
353         }
354
355         /* id tree */
356         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
357                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
358         {
359 #ifdef NEW_LOGGING
360                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
361                            "bdb_cache_add_entry: (%s):%ls already in cache.\n",
362                            e->e_dn, e->e_id ));
363 #else
364                 Debug( LDAP_DEBUG_ANY,
365                         "====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n",
366                     e->e_id, e->e_dn, 0 );
367 #endif
368
369
370
371                 /* delete from dn tree inserted above */
372                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
373                         (AVL_CMP) entry_dn_cmp ) == NULL )
374                 {
375 #ifdef NEW_LOGGING
376                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
377                                    "bdb_cache_add_entry: can't delete (%s) from cache.\n",
378                                    e->e_dn ));
379 #else
380                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
381                             0, 0, 0 );
382 #endif
383
384                 }
385
386                 bdb_cache_entry_private_destroy(e);
387
388                 /* free cache mutex */
389                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
390                 return( -1 );
391         }
392
393         bdb_cache_entry_rdwr_lock( e, rw );
394
395         /* put the entry into 'CREATING' state */
396         /* will be marked after when entry is returned */
397         BEI(e)->bei_state = CACHE_ENTRY_CREATING;
398         BEI(e)->bei_refcnt = 1;
399
400         /* lru */
401         LRU_ADD( cache, e );
402         if ( ++cache->c_cursize > cache->c_maxsize ) {
403                 /*
404                  * find the lru entry not currently in use and delete it.
405                  * in case a lot of entries are in use, only look at the
406                  * first 10 on the tail of the list.
407                  */
408                 i = 0;
409                 while ( cache->c_lrutail != NULL &&
410                         BEI(cache->c_lrutail)->bei_refcnt != 0 &&
411                         i < 10 )
412                 {
413                         /* move this in-use entry to the front of the q */
414                         ee = cache->c_lrutail;
415                         LRU_DELETE( cache, ee );
416                         LRU_ADD( cache, ee );
417                         i++;
418                 }
419
420                 /*
421                  * found at least one to delete - try to get back under
422                  * the max cache size.
423                  */
424                 while ( cache->c_lrutail != NULL &&
425                         BEI(cache->c_lrutail)->bei_refcnt == 0 &&
426                         cache->c_cursize > cache->c_maxsize )
427                 {
428                         e = cache->c_lrutail;
429
430                         /* delete from cache and lru q */
431                         /* XXX do we need rc ? */
432                         rc = bdb_cache_delete_entry_internal( cache, e );
433                         bdb_cache_entry_private_destroy( e );
434                         bdb_entry_return( e );
435                 }
436         }
437
438         /* free cache mutex */
439         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
440         return( 0 );
441 }
442
443 /*
444  * cache_update_entry - update a LOCKED entry which has been deleted.
445  * returns:     0       entry has been created and locked
446  *              1       entry already existed
447  *              -1      something bad happened
448  */
449 int
450 bdb_cache_update_entry(
451     Cache       *cache,
452     Entry               *e
453 )
454 {
455         int     i, rc;
456         Entry   *ee;
457
458         /* set cache mutex */
459         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
460
461         assert( e->e_private );
462
463         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
464                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
465         {
466 #ifdef NEW_LOGGING
467                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
468                            "bdb_cache_update_entry: (%s):%ld already in dn cache\n",
469                            e->e_dn, e->e_id ));
470 #else
471                 Debug( LDAP_DEBUG_TRACE,
472                         "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n",
473                     e->e_id, e->e_dn, 0 );
474 #endif
475
476
477                 /* free cache mutex */
478                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
479                 return( 1 );
480         }
481
482         /* id tree */
483         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
484                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
485         {
486 #ifdef NEW_LOGGING
487                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
488                            "bdb_cache_update_entry: (%s)%ld already in id cache\n",
489                            e->e_dn, e->e_id ));
490 #else
491                 Debug( LDAP_DEBUG_ANY,
492                         "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n",
493                     e->e_id, e->e_dn, 0 );
494 #endif
495
496
497                 /* delete from dn tree inserted above */
498                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
499                         (AVL_CMP) entry_dn_cmp ) == NULL )
500                 {
501 #ifdef NEW_LOGGING
502                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
503                                    "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n",
504                                    e->e_dn, e->e_id ));
505 #else
506                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
507                             0, 0, 0 );
508 #endif
509
510                 }
511
512                 /* free cache mutex */
513                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
514                 return( -1 );
515         }
516
517
518         /* put the entry into 'CREATING' state */
519         /* will be marked after when entry is returned */
520         BEI(e)->bei_state = CACHE_ENTRY_CREATING;
521
522         /* lru */
523         LRU_ADD( cache, e );
524         if ( ++cache->c_cursize > cache->c_maxsize ) {
525                 /*
526                  * find the lru entry not currently in use and delete it.
527                  * in case a lot of entries are in use, only look at the
528                  * first 10 on the tail of the list.
529                  */
530                 i = 0;
531                 while ( cache->c_lrutail != NULL &&
532                         BEI(cache->c_lrutail)->bei_refcnt != 0 &&
533                         i < 10 )
534                 {
535                         /* move this in-use entry to the front of the q */
536                         ee = cache->c_lrutail;
537                         LRU_DELETE( cache, ee );
538                         LRU_ADD( cache, ee );
539                         i++;
540                 }
541
542                 /*
543                  * found at least one to delete - try to get back under
544                  * the max cache size.
545                  */
546                 while ( cache->c_lrutail != NULL &&
547                         BEI(cache->c_lrutail)->bei_refcnt == 0 &&
548                         cache->c_cursize > cache->c_maxsize )
549                 {
550                         e = cache->c_lrutail;
551
552                         /* delete from cache and lru q */
553                         /* XXX do we need rc ? */
554                         rc = bdb_cache_delete_entry_internal( cache, e );
555                         bdb_cache_entry_private_destroy( e );
556                         bdb_entry_return( e );
557                 }
558         }
559
560         /* free cache mutex */
561         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
562         return( 0 );
563 }
564
565 ID
566 bdb_cache_find_entry_ndn2id(
567         Backend         *be,
568     Cache       *cache,
569     struct berval       *ndn
570 )
571 {
572         Entry           e, *ep;
573         ID                      id;
574         int count = 0;
575
576         /* this function is always called with normalized DN */
577         e.e_nname = *ndn;
578
579 try_again:
580         /* set cache mutex */
581         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
582
583         if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
584                 (AVL_CMP) entry_dn_cmp )) != NULL )
585         {
586                 int state;
587                 count++;
588
589                 /*
590                  * ep now points to an unlocked entry
591                  * we do not need to lock the entry if we only
592                  * check the state, refcnt, LRU, and id.
593                  */
594
595                 assert( ep->e_private );
596
597                 /* save id */
598                 id = ep->e_id;
599                 state = BEI(ep)->bei_state;
600
601                 /*
602                  * entry is deleted or not fully created yet
603                  */
604                 if ( state != CACHE_ENTRY_READY ) {
605                         assert(state != CACHE_ENTRY_UNDEFINED);
606
607                         /* free cache mutex */
608                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
609
610 #ifdef NEW_LOGGING
611                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
612                                    "bdb_cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
613                                    ndn->bv_val, id, state ));
614 #else
615                         Debug(LDAP_DEBUG_TRACE,
616                                 "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
617                                 ndn->bv_val, id, state);
618 #endif
619
620
621                         ldap_pvt_thread_yield();
622                         goto try_again;
623                 }
624
625                 /* lru */
626                 LRU_DELETE( cache, ep );
627                 LRU_ADD( cache, ep );
628                 
629                 /* free cache mutex */
630                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
631
632 #ifdef NEW_LOGGING
633                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
634                            "bdb_cache_find_entry_dn2id: (%s): %ld %d tries\n",
635                            ndn->bv_val, id, count ));
636 #else
637                 Debug(LDAP_DEBUG_TRACE,
638                         "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
639                         ndn->bv_val, id, count);
640 #endif
641
642
643         } else {
644                 /* free cache mutex */
645                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
646
647                 id = NOID;
648         }
649
650         return( id );
651 }
652
653 /*
654  * cache_find_entry_id - find an entry in the cache, given id
655  */
656
657 Entry *
658 bdb_cache_find_entry_id(
659         Cache   *cache,
660         ID                              id,
661         int                             rw
662 )
663 {
664         Entry   e;
665         Entry   *ep;
666         int     count = 0;
667
668         e.e_id = id;
669
670 try_again:
671         /* set cache mutex */
672         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
673
674         if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
675                 (AVL_CMP) entry_id_cmp )) != NULL )
676         {
677                 int state;
678                 ID      ep_id;
679
680                 count++;
681
682                 assert( ep->e_private );
683
684                 ep_id = ep->e_id; 
685                 state = BEI(ep)->bei_state;
686
687                 /*
688                  * entry is deleted or not fully created yet
689                  */
690                 if ( state != CACHE_ENTRY_READY ) {
691
692                         assert(state != CACHE_ENTRY_UNDEFINED);
693
694                         /* free cache mutex */
695                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
696
697 #ifdef NEW_LOGGING
698                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
699                                    "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
700                                    id, ep_id, state ));
701                                    
702 #else
703                         Debug(LDAP_DEBUG_TRACE,
704                                 "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n",
705                                 id, ep_id, state);
706 #endif
707
708
709                         ldap_pvt_thread_yield();
710                         goto try_again;
711                 }
712
713                 /* acquire reader lock */
714                 if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
715                         /* could not acquire entry lock...
716                          * owner cannot free as we have the cache locked.
717                          * so, unlock the cache, yield, and try again.
718                          */
719
720                         /* free cache mutex */
721                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
722
723 #ifdef NEW_LOGGING
724                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
725                                    "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n",
726                                    id, ep_id, state ));
727 #else
728                         Debug(LDAP_DEBUG_TRACE,
729                                 "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n",
730                                 id, ep_id, state);
731 #endif
732
733
734                         ldap_pvt_thread_yield();
735                         goto try_again;
736                 }
737
738                 /* lru */
739                 LRU_DELETE( cache, ep );
740                 LRU_ADD( cache, ep );
741                 
742                 BEI(ep)->bei_refcnt++;
743
744                 /* free cache mutex */
745                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
746
747 #ifdef NEW_LOGGING
748                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
749                            "bdb_cache_find_entry_id: %ld -> %s  found %d tries.\n",
750                            ep_id, ep->e_dn, count ));
751 #else
752                 Debug(LDAP_DEBUG_TRACE,
753                         "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
754                         ep_id, ep->e_dn, count);
755 #endif
756
757
758                 return( ep );
759         }
760
761         /* free cache mutex */
762         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
763
764         return( NULL );
765 }
766
767 /*
768  * cache_delete_entry - delete the entry e from the cache.  the caller
769  * should have obtained e (increasing its ref count) via a call to one
770  * of the cache_find_* routines.  the caller should *not* call the
771  * cache_return_entry() routine prior to calling cache_delete_entry().
772  * it performs this function.
773  *
774  * returns:     0       e was deleted ok
775  *              1       e was not in the cache
776  *              -1      something bad happened
777  */
778 int
779 bdb_cache_delete_entry(
780     Cache       *cache,
781     Entry               *e
782 )
783 {
784         int     rc;
785
786         /* set cache mutex */
787         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
788
789         assert( e->e_private );
790
791 #ifdef NEW_LOGGING
792         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
793                    "bdb_cache_delete_entry: delete %ld.\n", e->e_id ));
794 #else
795         Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n",
796                 e->e_id, 0, 0 );
797 #endif
798
799
800         rc = bdb_cache_delete_entry_internal( cache, e );
801
802         /* free cache mutex */
803         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
804         return( rc );
805 }
806
807 static int
808 bdb_cache_delete_entry_internal(
809     Cache       *cache,
810     Entry               *e
811 )
812 {
813         int rc = 0;     /* return code */
814
815         /* dn tree */
816         if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
817                 == NULL )
818         {
819                 rc = -1;
820         }
821
822         /* id tree */
823         if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
824                 == NULL )
825         {
826                 rc = -1;
827         }
828
829         if (rc != 0) {
830                 return rc;
831         }
832
833         /* lru */
834         LRU_DELETE( cache, e );
835         cache->c_cursize--;
836
837         /*
838          * flag entry to be freed later by a call to cache_return_entry()
839          */
840         BEI(e)->bei_state = CACHE_ENTRY_DELETED;
841
842         return( 0 );
843 }
844
845 void
846 bdb_cache_release_all( Cache *cache )
847 {
848         Entry *e;
849         int rc;
850
851         /* set cache mutex */
852         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
853
854 #ifdef NEW_LOGGING
855         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
856                    "bdb_cache_release_all: enter\n" ));
857 #else
858         Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 );
859 #endif
860
861
862         while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) {
863 #ifdef LDAP_RDWR_DEBUG
864                 assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr));
865 #endif
866
867                 /* delete from cache and lru q */
868                 /* XXX do we need rc ? */
869                 rc = bdb_cache_delete_entry_internal( cache, e );
870                 bdb_cache_entry_private_destroy( e );
871                 bdb_entry_return( e );
872         }
873
874         if ( cache->c_cursize ) {
875 #ifdef NEW_LOGGING
876                 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
877                            "bdb_cache_release_all: Entry cache could not be emptied.\n" ));
878 #else
879                 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
880 #endif
881
882         }
883
884         /* free cache mutex */
885         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
886 }
887
888 #ifdef LDAP_DEBUG
889
890 static void
891 bdb_lru_print( Cache *cache )
892 {
893         Entry   *e;
894
895         fprintf( stderr, "LRU queue (head to tail):\n" );
896         for ( e = cache->c_lruhead; e != NULL; e = BEI(e)->bei_lrunext ) {
897                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
898                         e->e_dn, e->e_id, BEI(e)->bei_refcnt );
899         }
900         fprintf( stderr, "LRU queue (tail to head):\n" );
901         for ( e = cache->c_lrutail; e != NULL; e = BEI(e)->bei_lruprev ) {
902                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
903                         e->e_dn, e->e_id, BEI(e)->bei_refcnt );
904         }
905 }
906
907 #endif