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