]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/cache.c
Fix matched values bug
[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 int
136 bdb_cache_entry_db_lock
137 ( DB_ENV *env, u_int32_t locker, Entry *e, int rw, u_int32_t flags, DB_LOCK *lock )
138 {
139         int       rc;
140         DBT       lockobj;
141         int       db_rw;
142
143         if (rw)
144                 db_rw = DB_LOCK_WRITE;
145         else
146                 db_rw = DB_LOCK_READ;
147
148         lockobj.data = e->e_nname.bv_val;
149         lockobj.size = e->e_nname.bv_len;
150         rc = LOCK_GET(env, locker, flags | DB_LOCK_NOWAIT,
151                                         &lockobj, db_rw, lock);
152         return rc;
153 }
154
155 int
156 bdb_cache_entry_db_unlock
157 ( DB_ENV *env, DB_LOCK *lock )
158 {
159         int rc;
160
161         rc = LOCK_PUT ( env, lock );
162         return rc;
163 }
164
165 /*
166  * marks an entry in CREATING state as committed, so it is really returned
167  * to the cache. Otherwise an entry in CREATING state is removed.
168  * Makes e_private be destroyed at the following cache_return_entry_w,
169  * but lets the entry untouched (owned by someone else)
170  */
171 void
172 bdb_cache_entry_commit( Entry *e )
173 {
174         assert( e );
175         assert( e->e_private );
176         assert( BEI(e)->bei_state == CACHE_ENTRY_CREATING );
177         /* assert( BEI(e)->bei_refcnt == 1 ); */
178
179         BEI(e)->bei_state = CACHE_ENTRY_COMMITTED;
180 }
181
182 static int
183 bdb_cache_entry_private_destroy( Entry *e )
184 {
185         assert( e->e_private );
186
187         bdb_cache_entry_rdwr_destroy( e );
188
189         free( e->e_private );
190         e->e_private = NULL;
191         return 0;
192 }
193
194 void
195 bdb_unlocked_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
196 {
197
198         ID id;
199         int refcnt, freeit = 1;
200
201         /* set cache write lock */
202         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
203
204         assert( e->e_private );
205
206 #if 0
207         bdb_cache_entry_rdwr_unlock(e, rw);
208 #endif
209
210         id = e->e_id;
211         refcnt = --BEI(e)->bei_refcnt;
212
213         /*
214          * if the entry is returned when in CREATING state, it is deleted
215          * but not freed because it may belong to someone else (do_add,
216          * for instance)
217          */
218         if (  BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
219                 /* set lru mutex */
220                 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
221                 bdb_cache_delete_entry_internal( cache, e );
222                 /* free lru mutex */
223                 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
224                 freeit = 0;
225                 /* now the entry is in DELETED state */
226         }
227
228         if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
229                 BEI(e)->bei_state = CACHE_ENTRY_READY;
230
231                 /* free cache write lock */
232                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
233
234 #ifdef NEW_LOGGING
235                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
236                            "bdb_unlocked_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
237                            id, rw ? "w" : "r", refcnt ));
238 #else
239                 Debug( LDAP_DEBUG_TRACE,
240                         "====> bdb_unlocked_cache_return_entry_%s( %ld ): created (%d)\n",
241                         rw ? "w" : "r", id, refcnt );
242 #endif
243
244
245         } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
246                 if( refcnt > 0 ) {
247                         /* free cache write lock */
248                         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
249
250 #ifdef NEW_LOGGING
251                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
252                                    "bdb_unlocked_cache_return_entry_rw: %ld, delete pending (%d).\n",
253                                    id, refcnt ));
254 #else
255                         Debug( LDAP_DEBUG_TRACE,
256                                 "====> bdb_unlocked_cache_return_entry_%s( %ld ): delete pending (%d)\n",
257                                 rw ? "w" : "r", id, refcnt );
258 #endif
259
260                 } else {
261                         bdb_cache_entry_private_destroy( e );
262                         if ( freeit ) {
263                                 bdb_entry_return( e );
264                         }
265
266                         /* free cache write lock */
267                         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
268
269 #ifdef NEW_LOGGING
270                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
271                                    "bdb_unlocked_cache_return_entry_rw: (%ld): deleted (%d)\n",
272                                    id, refcnt ));
273 #else
274                         Debug( LDAP_DEBUG_TRACE,
275                                 "====> bdb_unlocked_cache_return_entry_%s( %ld ): deleted (%d)\n",
276                                 rw ? "w" : "r", id, refcnt );
277 #endif
278                 }
279
280         } else {
281                 /* free cache write lock */
282                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
283
284 #ifdef NEW_LOGGING
285                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
286                            "bdb_unlocked_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
287                            id, rw ? "w": "r", refcnt ));
288 #else
289                 Debug( LDAP_DEBUG_TRACE,
290                         "====> bdb_unlocked_cache_return_entry_%s( %ld ): returned (%d)\n",
291                         rw ? "w" : "r", id, refcnt);
292 #endif
293         }
294 }
295
296 void
297 bdb_cache_return_entry_rw
298 ( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock )
299 {
300         ID id;
301         int refcnt, freeit = 1;
302
303         /* set cache write lock */
304         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
305
306         assert( e->e_private );
307
308         bdb_cache_entry_db_unlock( env, lock );
309 #if 0
310         bdb_cache_entry_rdwr_unlock(e, rw);
311 #endif
312
313         id = e->e_id;
314         refcnt = --BEI(e)->bei_refcnt;
315
316         /*
317          * if the entry is returned when in CREATING state, it is deleted
318          * but not freed because it may belong to someone else (do_add,
319          * for instance)
320          */
321         if (  BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
322                 /* set lru mutex */
323                 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
324                 bdb_cache_delete_entry_internal( cache, e );
325                 /* free lru mutex */
326                 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
327                 freeit = 0;
328                 /* now the entry is in DELETED state */
329         }
330
331         if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
332                 BEI(e)->bei_state = CACHE_ENTRY_READY;
333
334                 /* free cache write lock */
335                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
336
337 #ifdef NEW_LOGGING
338                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
339                            "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
340                            id, rw ? "w" : "r", refcnt ));
341 #else
342                 Debug( LDAP_DEBUG_TRACE,
343                         "====> bdb_cache_return_entry_%s( %ld ): created (%d)\n",
344                         rw ? "w" : "r", id, refcnt );
345 #endif
346
347
348         } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
349                 if( refcnt > 0 ) {
350                         /* free cache write lock */
351                         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
352
353 #ifdef NEW_LOGGING
354                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
355                                    "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n",
356                                    id, refcnt ));
357 #else
358                         Debug( LDAP_DEBUG_TRACE,
359                                 "====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n",
360                                 rw ? "w" : "r", id, refcnt );
361 #endif
362
363                 } else {
364                         bdb_cache_entry_private_destroy( e );
365                         if ( freeit ) {
366                                 bdb_entry_return( e );
367                         }
368
369                         /* free cache write lock */
370                         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
371
372 #ifdef NEW_LOGGING
373                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
374                                    "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n",
375                                    id, refcnt ));
376 #else
377                         Debug( LDAP_DEBUG_TRACE,
378                                 "====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n",
379                                 rw ? "w" : "r", id, refcnt );
380 #endif
381                 }
382
383         } else {
384                 /* free cache write lock */
385                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
386
387 #ifdef NEW_LOGGING
388                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
389                            "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
390                            id, rw ? "w": "r", refcnt ));
391 #else
392                 Debug( LDAP_DEBUG_TRACE,
393                         "====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n",
394                         rw ? "w" : "r", id, refcnt);
395 #endif
396         }
397 }
398
399 #define LRU_DELETE( cache, e ) do { \
400         if ( BEI(e)->bei_lruprev != NULL ) { \
401                 BEI(BEI(e)->bei_lruprev)->bei_lrunext = BEI(e)->bei_lrunext; \
402         } else { \
403                 (cache)->c_lruhead = BEI(e)->bei_lrunext; \
404         } \
405         if ( BEI(e)->bei_lrunext != NULL ) { \
406                 BEI(BEI(e)->bei_lrunext)->bei_lruprev = BEI(e)->bei_lruprev; \
407         } else { \
408                 (cache)->c_lrutail = BEI(e)->bei_lruprev; \
409         } \
410 } while(0)
411
412 #define LRU_ADD( cache, e ) do { \
413         BEI(e)->bei_lrunext = (cache)->c_lruhead; \
414         if ( BEI(e)->bei_lrunext != NULL ) { \
415                 BEI(BEI(e)->bei_lrunext)->bei_lruprev = (e); \
416         } \
417         (cache)->c_lruhead = (e); \
418         BEI(e)->bei_lruprev = NULL; \
419         if ( (cache)->c_lrutail == NULL ) { \
420                 (cache)->c_lrutail = (e); \
421         } \
422 } while(0)
423
424 /*
425  * cache_add_entry_rw - create and lock an entry in the cache
426  * returns:     0       entry has been created and locked
427  *              1       entry already existed
428  *              -1      something bad happened
429  *             other    Berkeley DB locking error code
430  */
431 int
432 bdb_cache_add_entry_rw(
433     DB_ENV      *env,
434     Cache       *cache,
435     Entry       *e,
436     int         rw,
437     u_int32_t   locker,
438     DB_LOCK     *lock
439 )
440 {
441         int     i, rc;
442         Entry   *ee;
443
444 #ifdef NEW_LOGGING
445         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
446                    "bdb_cache_add_entry_rw: add (%s):%s to cache\n",
447                    e->e_dn, rw ? "w" : "r" ));
448 #endif
449         /* set cache write lock */
450         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
451
452         assert( e->e_private == NULL );
453
454         if( bdb_cache_entry_private_init(e) != 0 ) {
455                 /* free cache write lock */
456                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
457
458 #ifdef NEW_LOGGING
459                 LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
460                            "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n",
461                            e->e_dn, e->e_id ));
462 #else
463                 Debug( LDAP_DEBUG_ANY,
464                         "====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n",
465                     e->e_id, e->e_dn, 0 );
466 #endif
467
468
469                 return( -1 );
470         }
471
472         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
473                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
474         {
475                 /* free cache write lock */
476                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
477
478 #ifdef NEW_LOGGING
479                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
480                            "bdb_cache_add_entry: (%s):%ld already in cache.\n",
481                            e->e_dn, e->e_id ));
482 #else
483                 Debug( LDAP_DEBUG_TRACE,
484                         "====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n",
485                     e->e_id, e->e_dn, 0 );
486 #endif
487
488                 bdb_cache_entry_private_destroy(e);
489
490                 return( 1 );
491         }
492
493         /* id tree */
494         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
495                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
496         {
497 #ifdef NEW_LOGGING
498                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
499                            "bdb_cache_add_entry: (%s):%ls already in cache.\n",
500                            e->e_dn, e->e_id ));
501 #else
502                 Debug( LDAP_DEBUG_ANY,
503                         "====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n",
504                     e->e_id, e->e_dn, 0 );
505 #endif
506
507                 /* delete from dn tree inserted above */
508                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
509                         (AVL_CMP) entry_dn_cmp ) == NULL )
510                 {
511 #ifdef NEW_LOGGING
512                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
513                                    "bdb_cache_add_entry: can't delete (%s) from cache.\n",
514                                    e->e_dn ));
515 #else
516                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
517                             0, 0, 0 );
518 #endif
519                 }
520
521                 bdb_cache_entry_private_destroy(e);
522
523                 /* free cache write lock */
524                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
525                 return( -1 );
526         }
527
528         rc = bdb_cache_entry_db_lock( env, locker, e, rw, 0, lock );
529         switch ( rc ) {
530         case 0 :
531                 break;
532         case DB_LOCK_DEADLOCK :
533         case DB_LOCK_NOTGRANTED :
534                 /* undo avl changes immediately */
535                 if ( avl_delete( &cache->c_idtree, (caddr_t) e,
536                         (AVL_CMP) entry_id_cmp ) == NULL ) {
537 #ifdef NEW_LOGGING
538                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
539                                 "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn ));
540 #else
541                         Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 );
542 #endif
543                 }
544                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
545                                 (AVL_CMP) entry_dn_cmp ) == NULL ) {
546 #ifdef NEW_LOGGING
547                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
548                                         "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn ));
549 #else
550                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 );
551 #endif
552                 }
553                 /* fall through */
554         default :
555                 bdb_cache_entry_private_destroy(e);
556                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
557                 return rc;
558         }
559
560         /* put the entry into 'CREATING' state */
561         /* will be marked after when entry is returned */
562         BEI(e)->bei_state = CACHE_ENTRY_CREATING;
563         BEI(e)->bei_refcnt = 1;
564
565         /* set lru mutex */
566         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
567         /* lru */
568         LRU_ADD( cache, e );
569         if ( ++cache->c_cursize > cache->c_maxsize ) {
570                 /*
571                  * find the lru entry not currently in use and delete it.
572                  * in case a lot of entries are in use, only look at the
573                  * first 10 on the tail of the list.
574                  */
575                 i = 0;
576                 while ( cache->c_lrutail != NULL &&
577                         BEI(cache->c_lrutail)->bei_refcnt != 0 &&
578                         i < 10 )
579                 {
580                         /* move this in-use entry to the front of the q */
581                         ee = cache->c_lrutail;
582                         LRU_DELETE( cache, ee );
583                         LRU_ADD( cache, ee );
584                         i++;
585                 }
586
587                 /*
588                  * found at least one to delete - try to get back under
589                  * the max cache size.
590                  */
591                 while ( cache->c_lrutail != NULL &&
592                         BEI(cache->c_lrutail)->bei_refcnt == 0 &&
593                         cache->c_cursize > cache->c_maxsize )
594                 {
595                         e = cache->c_lrutail;
596
597                         /* delete from cache and lru q */
598                         /* XXX do we need rc ? */
599                         rc = bdb_cache_delete_entry_internal( cache, e );
600                         bdb_cache_entry_private_destroy( e );
601                         bdb_entry_return( e );
602                 }
603         }
604
605         /* free lru mutex */
606         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
607         /* free cache write lock */
608         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
609         return( 0 );
610 }
611
612 /*
613  * cache_update_entry - update a LOCKED entry which has been deleted.
614  * returns:     0       entry has been created and locked
615  *              1       entry already existed
616  *              -1      something bad happened
617  */
618 int
619 bdb_cache_update_entry(
620     Cache       *cache,
621     Entry               *e
622 )
623 {
624         int     i, rc;
625         Entry   *ee;
626
627         /* set cache write lock */
628         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
629
630         assert( e->e_private );
631
632         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
633                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
634         {
635 #ifdef NEW_LOGGING
636                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
637                            "bdb_cache_update_entry: (%s):%ld already in dn cache\n",
638                            e->e_dn, e->e_id ));
639 #else
640                 Debug( LDAP_DEBUG_TRACE,
641                         "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n",
642                     e->e_id, e->e_dn, 0 );
643 #endif
644
645                 /* free cache write lock */
646                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
647                 return( 1 );
648         }
649
650         /* id tree */
651         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
652                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
653         {
654 #ifdef NEW_LOGGING
655                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
656                            "bdb_cache_update_entry: (%s)%ld already in id cache\n",
657                            e->e_dn, e->e_id ));
658 #else
659                 Debug( LDAP_DEBUG_ANY,
660                         "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n",
661                     e->e_id, e->e_dn, 0 );
662 #endif
663
664                 /* delete from dn tree inserted above */
665                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
666                         (AVL_CMP) entry_dn_cmp ) == NULL )
667                 {
668 #ifdef NEW_LOGGING
669                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
670                                    "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n",
671                                    e->e_dn, e->e_id ));
672 #else
673                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
674                             0, 0, 0 );
675 #endif
676                 }
677
678                 /* free cache write lock */
679                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
680                 return( -1 );
681         }
682
683
684         /* put the entry into 'CREATING' state */
685         /* will be marked after when entry is returned */
686         BEI(e)->bei_state = CACHE_ENTRY_CREATING;
687
688         /* set lru mutex */
689         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
690         /* lru */
691         LRU_ADD( cache, e );
692         if ( ++cache->c_cursize > cache->c_maxsize ) {
693                 /*
694                  * find the lru entry not currently in use and delete it.
695                  * in case a lot of entries are in use, only look at the
696                  * first 10 on the tail of the list.
697                  */
698                 i = 0;
699                 while ( cache->c_lrutail != NULL &&
700                         BEI(cache->c_lrutail)->bei_refcnt != 0 &&
701                         i < 10 )
702                 {
703                         /* move this in-use entry to the front of the q */
704                         ee = cache->c_lrutail;
705                         LRU_DELETE( cache, ee );
706                         LRU_ADD( cache, ee );
707                         i++;
708                 }
709
710                 /*
711                  * found at least one to delete - try to get back under
712                  * the max cache size.
713                  */
714                 while ( cache->c_lrutail != NULL &&
715                         BEI(cache->c_lrutail)->bei_refcnt == 0 &&
716                         cache->c_cursize > cache->c_maxsize )
717                 {
718                         e = cache->c_lrutail;
719
720                         /* delete from cache and lru q */
721                         /* XXX do we need rc ? */
722                         rc = bdb_cache_delete_entry_internal( cache, e );
723                         bdb_cache_entry_private_destroy( e );
724                         bdb_entry_return( e );
725                 }
726         }
727
728         /* free lru mutex */
729         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
730         /* free cache write lock */
731         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
732         return( 0 );
733 }
734
735 ID
736 bdb_cache_find_entry_ndn2id(
737         Backend         *be,
738     Cache       *cache,
739     struct berval       *ndn
740 )
741 {
742         Entry           e, *ep;
743         ID                      id;
744         int count = 0;
745
746         /* this function is always called with normalized DN */
747         e.e_nname = *ndn;
748
749 try_again:
750         /* set cache read lock */
751         ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
752
753         if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
754                 (AVL_CMP) entry_dn_cmp )) != NULL )
755         {
756                 int state;
757                 count++;
758
759                 /*
760                  * ep now points to an unlocked entry
761                  * we do not need to lock the entry if we only
762                  * check the state, refcnt, LRU, and id.
763                  */
764
765                 assert( ep->e_private );
766
767                 /* save id */
768                 id = ep->e_id;
769                 state = BEI(ep)->bei_state;
770
771                 /*
772                  * entry is deleted or not fully created yet
773                  */
774                 if ( state != CACHE_ENTRY_READY ) {
775                         assert(state != CACHE_ENTRY_UNDEFINED);
776
777                         /* free cache read lock */
778                         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
779
780 #ifdef NEW_LOGGING
781                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
782                                    "bdb_cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
783                                    ndn->bv_val, id, state ));
784 #else
785                         Debug(LDAP_DEBUG_TRACE,
786                                 "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
787                                 ndn->bv_val, id, state);
788 #endif
789
790
791                         ldap_pvt_thread_yield();
792                         goto try_again;
793                 }
794
795                 /* free cache read lock */
796                 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
797
798                 /* set lru mutex */
799                 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
800
801                 /* lru */
802                 LRU_DELETE( cache, ep );
803                 LRU_ADD( cache, ep );
804                 
805                 /* free lru mutex */
806                 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
807
808 #ifdef NEW_LOGGING
809                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
810                            "bdb_cache_find_entry_dn2id: (%s): %ld %d tries\n",
811                            ndn->bv_val, id, count ));
812 #else
813                 Debug(LDAP_DEBUG_TRACE,
814                         "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
815                         ndn->bv_val, id, count);
816 #endif
817
818         } else {
819                 /* free cache read lock */
820                 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
821
822                 id = NOID;
823         }
824
825         return( id );
826 }
827
828 /*
829  * cache_find_entry_id - find an entry in the cache, given id
830  */
831
832 Entry *
833 bdb_cache_find_entry_id(
834         DB_ENV  *env,
835         Cache   *cache,
836         ID                              id,
837         int                             rw,
838         u_int32_t       locker,
839         DB_LOCK         *lock
840 )
841 {
842         Entry   e;
843         Entry   *ep;
844         int     count = 0;
845         int     rc;
846
847         e.e_id = id;
848
849 try_again:
850         /* set cache read lock */
851         ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
852
853         if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
854                 (AVL_CMP) entry_id_cmp )) != NULL )
855         {
856                 int state;
857                 ID      ep_id;
858
859                 count++;
860
861                 assert( ep->e_private );
862
863                 ep_id = ep->e_id; 
864                 state = BEI(ep)->bei_state;
865
866                 /*
867                  * entry is deleted or not fully created yet
868                  */
869                 if ( state != CACHE_ENTRY_READY ) {
870
871                         assert(state != CACHE_ENTRY_UNDEFINED);
872
873                         /* free cache read lock */
874                         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
875
876 #ifdef NEW_LOGGING
877                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
878                                    "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
879                                    id, ep_id, state ));
880                                    
881 #else
882                         Debug(LDAP_DEBUG_TRACE,
883                                 "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n",
884                                 id, ep_id, state);
885 #endif
886
887                         ldap_pvt_thread_yield();
888                         goto try_again;
889                 }
890
891                 /* acquire reader lock */
892                 rc = bdb_cache_entry_db_lock ( env, locker, ep, rw, 0, lock );
893
894 #if 0
895                 if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
896 #endif
897
898                 if ( rc ) { /* will be changed to retry beyond threshold */
899                         /* could not acquire entry lock...
900                          * owner cannot free as we have the cache locked.
901                          * so, unlock the cache, yield, and try again.
902                          */
903
904                         /* free cache read lock */
905                         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
906
907 #ifdef NEW_LOGGING
908                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
909                                    "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n",
910                                    id, ep_id, state ));
911 #else
912                         Debug(LDAP_DEBUG_TRACE,
913                                 "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n",
914                                 id, ep_id, state);
915                         Debug(LDAP_DEBUG_TRACE,
916                                 "locker = %d\n",
917                                 locker, 0, 0);
918 #endif
919
920                         ldap_pvt_thread_yield();
921                         goto try_again;
922                 }
923
924                 /* free cache read lock */
925                 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
926                 /* set lru mutex */
927                 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
928                 /* lru */
929                 LRU_DELETE( cache, ep );
930                 LRU_ADD( cache, ep );
931                 
932                 BEI(ep)->bei_refcnt++;
933
934                 /* free lru mutex */
935                 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
936
937 #ifdef NEW_LOGGING
938                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
939                            "bdb_cache_find_entry_id: %ld -> %s  found %d tries.\n",
940                            ep_id, ep->e_dn, count ));
941 #else
942                 Debug(LDAP_DEBUG_TRACE,
943                         "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
944                         ep_id, ep->e_dn, count);
945 #endif
946
947
948                 return( ep );
949         }
950
951         /* free cache read lock */
952         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
953
954         return( NULL );
955 }
956
957 /*
958  * cache_delete_entry - delete the entry e from the cache.  the caller
959  * should have obtained e (increasing its ref count) via a call to one
960  * of the cache_find_* routines.  the caller should *not* call the
961  * cache_return_entry() routine prior to calling cache_delete_entry().
962  * it performs this function.
963  *
964  * returns:     0       e was deleted ok
965  *              1       e was not in the cache
966  *              -1      something bad happened
967  */
968 int
969 bdb_cache_delete_entry(
970     Cache       *cache,
971     Entry               *e
972 )
973 {
974         int     rc;
975
976         /* set cache write lock */
977         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
978
979         assert( e->e_private );
980
981 #ifdef NEW_LOGGING
982         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
983                    "bdb_cache_delete_entry: delete %ld.\n", e->e_id ));
984 #else
985         Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n",
986                 e->e_id, 0, 0 );
987 #endif
988
989         /* set lru mutex */
990         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
991         rc = bdb_cache_delete_entry_internal( cache, e );
992         /* free lru mutex */
993         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
994
995         /* free cache write lock */
996         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
997         return( rc );
998 }
999
1000 static int
1001 bdb_cache_delete_entry_internal(
1002     Cache       *cache,
1003     Entry               *e
1004 )
1005 {
1006         int rc = 0;     /* return code */
1007
1008         /* dn tree */
1009         if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
1010                 == NULL )
1011         {
1012                 rc = -1;
1013         }
1014
1015         /* id tree */
1016         if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
1017                 == NULL )
1018         {
1019                 rc = -1;
1020         }
1021
1022         if (rc != 0) {
1023                 return rc;
1024         }
1025
1026         /* lru */
1027         LRU_DELETE( cache, e );
1028         cache->c_cursize--;
1029
1030         /*
1031          * flag entry to be freed later by a call to cache_return_entry()
1032          */
1033         BEI(e)->bei_state = CACHE_ENTRY_DELETED;
1034
1035         return( 0 );
1036 }
1037
1038 void
1039 bdb_cache_release_all( Cache *cache )
1040 {
1041         Entry *e;
1042         int rc;
1043
1044         /* set cache write lock */
1045         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
1046         /* set lru mutex */
1047         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
1048
1049 #ifdef NEW_LOGGING
1050         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
1051                    "bdb_cache_release_all: enter\n" ));
1052 #else
1053         Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 );
1054 #endif
1055
1056         while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) {
1057 #ifdef LDAP_RDWR_DEBUG
1058                 assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr));
1059 #endif
1060
1061                 /* delete from cache and lru q */
1062                 /* XXX do we need rc ? */
1063                 rc = bdb_cache_delete_entry_internal( cache, e );
1064                 bdb_cache_entry_private_destroy( e );
1065                 bdb_entry_return( e );
1066         }
1067
1068         if ( cache->c_cursize ) {
1069 #ifdef NEW_LOGGING
1070                 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
1071                            "bdb_cache_release_all: Entry cache could not be emptied.\n" ));
1072 #else
1073                 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
1074 #endif
1075
1076         }
1077
1078         /* free lru mutex */
1079         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
1080         /* free cache write lock */
1081         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
1082 }
1083
1084 #ifdef LDAP_DEBUG
1085 static void
1086 bdb_lru_print( Cache *cache )
1087 {
1088         Entry   *e;
1089
1090         fprintf( stderr, "LRU queue (head to tail):\n" );
1091         for ( e = cache->c_lruhead; e != NULL; e = BEI(e)->bei_lrunext ) {
1092                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
1093                         e->e_dn, e->e_id, BEI(e)->bei_refcnt );
1094         }
1095         fprintf( stderr, "LRU queue (tail to head):\n" );
1096         for ( e = cache->c_lrutail; e != NULL; e = BEI(e)->bei_lruprev ) {
1097                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
1098                         e->e_dn, e->e_id, BEI(e)->bei_refcnt );
1099         }
1100 }
1101 #endif