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