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