]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/cache.c
Add start of discussion of strings in LDAP/X.500 and OpenLDAP.
[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, ENTRY, 
53                 "bdb_cache_entry_rdwr_lock: %s lock on ID %ld\n",
54                 rw ? "w" : "r", e->e_id, 0 );
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, ENTRY, 
71                 "bdb_cache_entry_rdwr_trylock: try %s lock on ID: %ld.\n",
72                 rw ? "w" : "r", e->e_id, 0 );
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, ENTRY, 
89                 "bdb_cache_entry_rdwr_unlock: remove %s lock on ID %ld.\n",
90                 rw ? "w" : "r", e->e_id, 0 );
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, 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, DETAIL1, 
252                                    "bdb_unlocked_cache_return_entry_rw: %ld, delete pending (%d).\n",
253                                    id, refcnt, 0 );
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, DETAIL1, 
271                                    "bdb_unlocked_cache_return_entry_rw: (%ld): deleted (%d)\n",
272                                    id, refcnt, 0 );
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, 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, 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, DETAIL1, 
355                                    "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n",
356                                    id, refcnt, 0 );
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, DETAIL1, 
374                                    "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n",
375                                    id, refcnt, 0 );
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, 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, ENTRY, 
446                 "bdb_cache_add_entry_rw: add (%s):%s to cache\n",
447                 e->e_dn, rw ? "w" : "r", 0 );
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, ERR, 
460                         "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n",
461                         e->e_dn, e->e_id, 0 );
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, DETAIL1, 
480                         "bdb_cache_add_entry: (%s):%ld already in cache.\n",
481                         e->e_dn, e->e_id, 0 );
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, DETAIL1, 
499                         "bdb_cache_add_entry: (%s):%ls already in cache.\n",
500                         e->e_dn, e->e_id, 0 );
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, INFO, 
513                                 "bdb_cache_add_entry: can't delete (%s) from cache.\n", 
514                                 e->e_dn, 0, 0 );
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, INFO, 
539                                 "bdb_cache_add_entry: can't delete (%s) from cache.\n", 
540                                 e->e_dn, 0, 0 );
541 #else
542                         Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 );
543 #endif
544                 }
545                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
546                                 (AVL_CMP) entry_dn_cmp ) == NULL ) {
547 #ifdef NEW_LOGGING
548                         LDAP_LOG( CACHE, INFO, 
549                                 "bdb_cache_add_entry: can't delete (%s) from cache.\n", 
550                                 e->e_dn, 0, 0 );
551 #else
552                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 );
553 #endif
554                 }
555                 /* fall through */
556         default :
557                 bdb_cache_entry_private_destroy(e);
558                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
559                 return rc;
560         }
561
562         /* put the entry into 'CREATING' state */
563         /* will be marked after when entry is returned */
564         BEI(e)->bei_state = CACHE_ENTRY_CREATING;
565         BEI(e)->bei_refcnt = 1;
566
567         /* set lru mutex */
568         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
569         /* lru */
570         LRU_ADD( cache, e );
571         if ( ++cache->c_cursize > cache->c_maxsize ) {
572                 /*
573                  * find the lru entry not currently in use and delete it.
574                  * in case a lot of entries are in use, only look at the
575                  * first 10 on the tail of the list.
576                  */
577                 i = 0;
578                 while ( cache->c_lrutail != NULL &&
579                         BEI(cache->c_lrutail)->bei_refcnt != 0 &&
580                         i < 10 )
581                 {
582                         /* move this in-use entry to the front of the q */
583                         ee = cache->c_lrutail;
584                         LRU_DELETE( cache, ee );
585                         LRU_ADD( cache, ee );
586                         i++;
587                 }
588
589                 /*
590                  * found at least one to delete - try to get back under
591                  * the max cache size.
592                  */
593                 while ( cache->c_lrutail != NULL &&
594                         BEI(cache->c_lrutail)->bei_refcnt == 0 &&
595                         cache->c_cursize > cache->c_maxsize )
596                 {
597                         e = cache->c_lrutail;
598
599                         /* delete from cache and lru q */
600                         /* XXX do we need rc ? */
601                         rc = bdb_cache_delete_entry_internal( cache, e );
602                         bdb_cache_entry_private_destroy( e );
603                         bdb_entry_return( e );
604                 }
605         }
606
607         /* free lru mutex */
608         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
609         /* free cache write lock */
610         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
611         return( 0 );
612 }
613
614 /*
615  * cache_update_entry - update a LOCKED entry which has been deleted.
616  * returns:     0       entry has been created and locked
617  *              1       entry already existed
618  *              -1      something bad happened
619  */
620 int
621 bdb_cache_update_entry(
622     Cache       *cache,
623     Entry               *e
624 )
625 {
626         int     i, rc;
627         Entry   *ee;
628
629         /* set cache write lock */
630         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
631
632         assert( e->e_private );
633
634         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
635                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
636         {
637 #ifdef NEW_LOGGING
638                 LDAP_LOG( CACHE, DETAIL1, 
639                         "bdb_cache_update_entry: (%s):%ld already in dn cache\n",
640                         e->e_dn, e->e_id, 0 );
641 #else
642                 Debug( LDAP_DEBUG_TRACE,
643                         "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n",
644                     e->e_id, e->e_dn, 0 );
645 #endif
646
647                 /* free cache write lock */
648                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
649                 return( 1 );
650         }
651
652         /* id tree */
653         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
654                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
655         {
656 #ifdef NEW_LOGGING
657                 LDAP_LOG( CACHE, DETAIL1, 
658                         "bdb_cache_update_entry: (%s)%ld already in id cache\n",
659                         e->e_dn, e->e_id, 0 );
660 #else
661                 Debug( LDAP_DEBUG_ANY,
662                         "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n",
663                     e->e_id, e->e_dn, 0 );
664 #endif
665
666                 /* delete from dn tree inserted above */
667                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
668                         (AVL_CMP) entry_dn_cmp ) == NULL )
669                 {
670 #ifdef NEW_LOGGING
671                         LDAP_LOG( CACHE, INFO, 
672                                 "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n",
673                                 e->e_dn, e->e_id, 0 );
674 #else
675                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
676                             0, 0, 0 );
677 #endif
678                 }
679
680                 /* free cache write lock */
681                 ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
682                 return( -1 );
683         }
684
685
686         /* put the entry into 'CREATING' state */
687         /* will be marked after when entry is returned */
688         BEI(e)->bei_state = CACHE_ENTRY_CREATING;
689
690         /* set lru mutex */
691         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
692         /* lru */
693         LRU_ADD( cache, e );
694         if ( ++cache->c_cursize > cache->c_maxsize ) {
695                 /*
696                  * find the lru entry not currently in use and delete it.
697                  * in case a lot of entries are in use, only look at the
698                  * first 10 on the tail of the list.
699                  */
700                 i = 0;
701                 while ( cache->c_lrutail != NULL &&
702                         BEI(cache->c_lrutail)->bei_refcnt != 0 &&
703                         i < 10 )
704                 {
705                         /* move this in-use entry to the front of the q */
706                         ee = cache->c_lrutail;
707                         LRU_DELETE( cache, ee );
708                         LRU_ADD( cache, ee );
709                         i++;
710                 }
711
712                 /*
713                  * found at least one to delete - try to get back under
714                  * the max cache size.
715                  */
716                 while ( cache->c_lrutail != NULL &&
717                         BEI(cache->c_lrutail)->bei_refcnt == 0 &&
718                         cache->c_cursize > cache->c_maxsize )
719                 {
720                         e = cache->c_lrutail;
721
722                         /* delete from cache and lru q */
723                         /* XXX do we need rc ? */
724                         rc = bdb_cache_delete_entry_internal( cache, e );
725                         bdb_cache_entry_private_destroy( e );
726                         bdb_entry_return( e );
727                 }
728         }
729
730         /* free lru mutex */
731         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
732         /* free cache write lock */
733         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
734         return( 0 );
735 }
736
737 ID
738 bdb_cache_find_entry_ndn2id(
739         Backend         *be,
740     Cache       *cache,
741     struct berval       *ndn
742 )
743 {
744         Entry           e, *ep;
745         ID                      id;
746         int count = 0;
747
748         /* this function is always called with normalized DN */
749         e.e_nname = *ndn;
750
751 try_again:
752         /* set cache read lock */
753         ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
754
755         if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
756                 (AVL_CMP) entry_dn_cmp )) != NULL )
757         {
758                 int state;
759                 count++;
760
761                 /*
762                  * ep now points to an unlocked entry
763                  * we do not need to lock the entry if we only
764                  * check the state, refcnt, LRU, and id.
765                  */
766
767                 assert( ep->e_private );
768
769                 /* save id */
770                 id = ep->e_id;
771                 state = BEI(ep)->bei_state;
772
773                 /*
774                  * entry is deleted or not fully created yet
775                  */
776                 if ( state != CACHE_ENTRY_READY ) {
777                         assert(state != CACHE_ENTRY_UNDEFINED);
778
779                         /* free cache read lock */
780                         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
781
782 #ifdef NEW_LOGGING
783                         LDAP_LOG( CACHE, INFO, 
784                                 "bdb_cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
785                                 ndn->bv_val, id, state );
786 #else
787                         Debug(LDAP_DEBUG_TRACE,
788                                 "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
789                                 ndn->bv_val, id, state);
790 #endif
791
792
793                         ldap_pvt_thread_yield();
794                         goto try_again;
795                 }
796
797                 /* free cache read lock */
798                 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
799
800                 /* set lru mutex */
801                 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
802
803                 /* lru */
804                 LRU_DELETE( cache, ep );
805                 LRU_ADD( cache, ep );
806                 
807                 /* free lru mutex */
808                 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
809
810 #ifdef NEW_LOGGING
811                 LDAP_LOG( CACHE, DETAIL1, 
812                         "bdb_cache_find_entry_dn2id: (%s): %ld %d tries\n",
813                         ndn->bv_val, id, count );
814 #else
815                 Debug(LDAP_DEBUG_TRACE,
816                         "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
817                         ndn->bv_val, id, count);
818 #endif
819
820         } else {
821                 /* free cache read lock */
822                 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
823
824                 id = NOID;
825         }
826
827         return( id );
828 }
829
830 /*
831  * cache_find_entry_id - find an entry in the cache, given id
832  */
833
834 Entry *
835 bdb_cache_find_entry_id(
836         DB_ENV  *env,
837         Cache   *cache,
838         ID                              id,
839         int                             rw,
840         u_int32_t       locker,
841         DB_LOCK         *lock
842 )
843 {
844         Entry   e;
845         Entry   *ep;
846         int     count = 0;
847         int     rc;
848
849         e.e_id = id;
850
851 try_again:
852         /* set cache read lock */
853         ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock );
854
855         if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
856                 (AVL_CMP) entry_id_cmp )) != NULL )
857         {
858                 int state;
859                 ID      ep_id;
860
861                 count++;
862
863                 assert( ep->e_private );
864
865                 ep_id = ep->e_id; 
866                 state = BEI(ep)->bei_state;
867
868                 /*
869                  * entry is deleted or not fully created yet
870                  */
871                 if ( state != CACHE_ENTRY_READY ) {
872
873                         assert(state != CACHE_ENTRY_UNDEFINED);
874
875                         /* free cache read lock */
876                         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
877
878 #ifdef NEW_LOGGING
879                         LDAP_LOG( CACHE, INFO, 
880                                 "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
881                                 id, ep_id, state );
882                                    
883 #else
884                         Debug(LDAP_DEBUG_TRACE,
885                                 "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n",
886                                 id, ep_id, state);
887 #endif
888
889                         ldap_pvt_thread_yield();
890                         goto try_again;
891                 }
892
893                 /* acquire reader lock */
894                 rc = bdb_cache_entry_db_lock ( env, locker, ep, rw, 0, lock );
895
896 #if 0
897                 if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
898 #endif
899
900                 if ( rc ) { /* will be changed to retry beyond threshold */
901                         /* could not acquire entry lock...
902                          * owner cannot free as we have the cache locked.
903                          * so, unlock the cache, yield, and try again.
904                          */
905
906                         /* free cache read lock */
907                         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
908
909 #ifdef NEW_LOGGING
910                         LDAP_LOG( CACHE, INFO, 
911                                 "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n",
912                                 id, ep_id, state );
913 #else
914                         Debug(LDAP_DEBUG_TRACE,
915                                 "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n",
916                                 id, ep_id, state);
917                         Debug(LDAP_DEBUG_TRACE,
918                                 "locker = %d\n",
919                                 locker, 0, 0);
920 #endif
921
922                         ldap_pvt_thread_yield();
923                         goto try_again;
924                 }
925
926                 /* free cache read lock */
927                 ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
928                 /* set lru mutex */
929                 ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
930                 /* lru */
931                 LRU_DELETE( cache, ep );
932                 LRU_ADD( cache, ep );
933                 
934                 BEI(ep)->bei_refcnt++;
935
936                 /* free lru mutex */
937                 ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
938
939 #ifdef NEW_LOGGING
940                 LDAP_LOG( CACHE, DETAIL1, 
941                         "bdb_cache_find_entry_id: %ld -> %s  found %d tries.\n",
942                         ep_id, ep->e_dn, count );
943 #else
944                 Debug(LDAP_DEBUG_TRACE,
945                         "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
946                         ep_id, ep->e_dn, count);
947 #endif
948
949
950                 return( ep );
951         }
952
953         /* free cache read lock */
954         ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock );
955
956         return( NULL );
957 }
958
959 /*
960  * cache_delete_entry - delete the entry e from the cache.  the caller
961  * should have obtained e (increasing its ref count) via a call to one
962  * of the cache_find_* routines.  the caller should *not* call the
963  * cache_return_entry() routine prior to calling cache_delete_entry().
964  * it performs this function.
965  *
966  * returns:     0       e was deleted ok
967  *              1       e was not in the cache
968  *              -1      something bad happened
969  */
970 int
971 bdb_cache_delete_entry(
972     Cache       *cache,
973     Entry               *e
974 )
975 {
976         int     rc;
977
978         /* set cache write lock */
979         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
980
981         assert( e->e_private );
982
983 #ifdef NEW_LOGGING
984         LDAP_LOG( CACHE, ENTRY, 
985                 "bdb_cache_delete_entry: delete %ld.\n", e->e_id, 0, 0 );
986 #else
987         Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n",
988                 e->e_id, 0, 0 );
989 #endif
990
991         /* set lru mutex */
992         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
993         rc = bdb_cache_delete_entry_internal( cache, e );
994         /* free lru mutex */
995         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
996
997         /* free cache write lock */
998         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
999         return( rc );
1000 }
1001
1002 static int
1003 bdb_cache_delete_entry_internal(
1004     Cache       *cache,
1005     Entry               *e
1006 )
1007 {
1008         int rc = 0;     /* return code */
1009
1010         /* dn tree */
1011         if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
1012                 == NULL )
1013         {
1014                 rc = -1;
1015         }
1016
1017         /* id tree */
1018         if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
1019                 == NULL )
1020         {
1021                 rc = -1;
1022         }
1023
1024         if (rc != 0) {
1025                 return rc;
1026         }
1027
1028         /* lru */
1029         LRU_DELETE( cache, e );
1030         cache->c_cursize--;
1031
1032         /*
1033          * flag entry to be freed later by a call to cache_return_entry()
1034          */
1035         BEI(e)->bei_state = CACHE_ENTRY_DELETED;
1036
1037         return( 0 );
1038 }
1039
1040 void
1041 bdb_cache_release_all( Cache *cache )
1042 {
1043         Entry *e;
1044         int rc;
1045
1046         /* set cache write lock */
1047         ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
1048         /* set lru mutex */
1049         ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
1050
1051 #ifdef NEW_LOGGING
1052         LDAP_LOG( CACHE, ENTRY, "bdb_cache_release_all: enter\n", 0, 0, 0 );
1053 #else
1054         Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 );
1055 #endif
1056
1057         while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) {
1058 #ifdef LDAP_RDWR_DEBUG
1059                 assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr));
1060 #endif
1061
1062                 /* delete from cache and lru q */
1063                 /* XXX do we need rc ? */
1064                 rc = bdb_cache_delete_entry_internal( cache, e );
1065                 bdb_cache_entry_private_destroy( e );
1066                 bdb_entry_return( e );
1067         }
1068
1069         if ( cache->c_cursize ) {
1070 #ifdef NEW_LOGGING
1071                 LDAP_LOG( CACHE, INFO,
1072                    "bdb_cache_release_all: Entry cache could not be emptied.\n", 0, 0, 0 );
1073 #else
1074                 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
1075 #endif
1076
1077         }
1078
1079         /* free lru mutex */
1080         ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
1081         /* free cache write lock */
1082         ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
1083 }
1084
1085 #ifdef LDAP_DEBUG
1086 static void
1087 bdb_lru_print( Cache *cache )
1088 {
1089         Entry   *e;
1090
1091         fprintf( stderr, "LRU queue (head to tail):\n" );
1092         for ( e = cache->c_lruhead; e != NULL; e = BEI(e)->bei_lrunext ) {
1093                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
1094                         e->e_dn, e->e_id, BEI(e)->bei_refcnt );
1095         }
1096         fprintf( stderr, "LRU queue (tail to head):\n" );
1097         for ( e = cache->c_lrutail; e != NULL; e = BEI(e)->bei_lruprev ) {
1098                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
1099                         e->e_dn, e->e_id, BEI(e)->bei_refcnt );
1100         }
1101 }
1102 #endif