]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/cache.c
Suck in HEAD changes since 2.1alpha
[openldap] / servers / slapd / back-ldbm / 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-ldbm.h"
19
20 /* LDBM backend specific entry info -- visible only to the cache */
21 typedef struct ldbm_entry_info {
22         /*
23          * These items are specific to the LDBM backend and should
24          * be hidden.  Backend cache lock required to access.
25          */
26         int             lei_state;      /* for the cache */
27 #define CACHE_ENTRY_UNDEFINED   0
28 #define CACHE_ENTRY_CREATING    1
29 #define CACHE_ENTRY_READY       2
30 #define CACHE_ENTRY_DELETED     3
31 #define CACHE_ENTRY_COMMITTED   4
32         
33         int             lei_refcnt;     /* # threads ref'ing this entry */
34         Entry   *lei_lrunext;   /* for cache lru list */
35         Entry   *lei_lruprev;
36 } EntryInfo;
37 #undef LEI
38 #define LEI(e)  ((EntryInfo *) ((e)->e_private))
39
40 static int      cache_delete_entry_internal(Cache *cache, Entry *e);
41 #ifdef LDAP_DEBUG
42 static void     lru_print(Cache *cache);
43 #endif
44
45 static int
46 cache_entry_private_init( Entry*e )
47 {
48         assert( e->e_private == NULL );
49
50         if( e->e_private != NULL ) {
51                 /* this should never happen */
52                 return 1;
53         }
54
55         e->e_private = ch_calloc(1, sizeof(struct ldbm_entry_info));
56
57         return 0;
58 }
59
60 /*
61  * marks an entry in CREATING state as committed, so it is really returned
62  * to the cache. Otherwise an entry in CREATING state is removed.
63  * Makes e_private be destroyed at the following cache_return_entry_w,
64  * but lets the entry untouched (owned by someone else)
65  */
66 void
67 cache_entry_commit( Entry *e )
68 {
69         assert( e );
70         assert( e->e_private );
71         assert( LEI(e)->lei_state == CACHE_ENTRY_CREATING );
72         /* assert( LEI(e)->lei_refcnt == 1 ); */
73
74         LEI(e)->lei_state = CACHE_ENTRY_COMMITTED;
75 }
76
77 static int
78 cache_entry_private_destroy( Entry*e )
79 {
80         assert( e->e_private );
81
82         free( e->e_private );
83         e->e_private = NULL;
84         return 0;
85 }
86
87 void
88 cache_return_entry_rw( Cache *cache, Entry *e, int rw )
89 {
90         ID id;
91         int refcnt, freeit = 1;
92
93         /* set cache mutex */
94         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
95
96         assert( e->e_private );
97
98         id = e->e_id;
99         refcnt = --LEI(e)->lei_refcnt;
100
101         /*
102          * if the entry is returned when in CREATING state, it is deleted
103          * but not freed because it may belong to someone else (do_add,
104          * for instance)
105          */
106         if (  LEI(e)->lei_state == CACHE_ENTRY_CREATING ) {
107                 cache_delete_entry_internal( cache, e );
108                 freeit = 0;
109                 /* now the entry is in DELETED state */
110         }
111
112         if ( LEI(e)->lei_state == CACHE_ENTRY_COMMITTED ) {
113                 LEI(e)->lei_state = CACHE_ENTRY_READY;
114
115                 /* free cache mutex */
116                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
117
118 #ifdef NEW_LOGGING
119                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
120                            "cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
121                            id, rw ? "w" : "r", refcnt ));
122 #else
123                 Debug( LDAP_DEBUG_TRACE,
124                         "====> cache_return_entry_%s( %ld ): created (%d)\n",
125                         rw ? "w" : "r", id, refcnt );
126 #endif
127
128         } else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED ) {
129                 if( refcnt > 0 ) {
130                         /* free cache mutex */
131                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
132
133 #ifdef NEW_LOGGING
134                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
135                                    "cache_return_entry_rw: %ld, delete pending (%d).\n",
136                                    id, refcnt ));
137 #else
138                         Debug( LDAP_DEBUG_TRACE,
139                                 "====> cache_return_entry_%s( %ld ): delete pending (%d)\n",
140                                 rw ? "w" : "r", id, refcnt );
141 #endif
142
143                 } else {
144                         cache_entry_private_destroy( e );
145                         if ( freeit ) {
146                                 entry_free( e );
147                         }
148
149                         /* free cache mutex */
150                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
151
152 #ifdef NEW_LOGGING
153                         LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
154                                    "cache_return_entry_rw: (%ld): deleted (%d)\n",
155                                    id, refcnt ));
156 #else
157                         Debug( LDAP_DEBUG_TRACE,
158                                 "====> cache_return_entry_%s( %ld ): deleted (%d)\n",
159                                 rw ? "w" : "r", id, refcnt );
160 #endif
161                 }
162
163         } else {
164                 /* free cache mutex */
165                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
166
167 #ifdef NEW_LOGGING
168                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
169                            "cache_return_entry_rw: ID %ld:%s returned (%d)\n",
170                            id, rw ? "w": "r", refcnt ));
171 #else
172                 Debug( LDAP_DEBUG_TRACE,
173                         "====> cache_return_entry_%s( %ld ): returned (%d)\n",
174                         rw ? "w" : "r", id, refcnt);
175 #endif
176         }
177 }
178
179 #define LRU_DELETE( cache, e ) do { \
180         if ( LEI(e)->lei_lruprev != NULL ) { \
181                 LEI(LEI(e)->lei_lruprev)->lei_lrunext = LEI(e)->lei_lrunext; \
182         } else { \
183                 (cache)->c_lruhead = LEI(e)->lei_lrunext; \
184         } \
185         if ( LEI(e)->lei_lrunext != NULL ) { \
186                 LEI(LEI(e)->lei_lrunext)->lei_lruprev = LEI(e)->lei_lruprev; \
187         } else { \
188                 (cache)->c_lrutail = LEI(e)->lei_lruprev; \
189         } \
190 } while(0)
191
192 #define LRU_ADD( cache, e ) do { \
193         LEI(e)->lei_lrunext = (cache)->c_lruhead; \
194         if ( LEI(e)->lei_lrunext != NULL ) { \
195                 LEI(LEI(e)->lei_lrunext)->lei_lruprev = (e); \
196         } \
197         (cache)->c_lruhead = (e); \
198         LEI(e)->lei_lruprev = NULL; \
199         if ( (cache)->c_lrutail == NULL ) { \
200                 (cache)->c_lrutail = (e); \
201         } \
202 } while(0)
203
204 /*
205  * cache_add_entry_rw - create and lock an entry in the cache
206  * returns:     0       entry has been created and locked
207  *              1       entry already existed
208  *              -1      something bad happened
209  */
210 int
211 cache_add_entry_rw(
212     Cache       *cache,
213     Entry               *e,
214         int             rw
215 )
216 {
217         int     i, rc;
218         Entry   *ee;
219
220 #ifdef NEW_LOGGING
221         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
222                    "cache_add_entry_rw: add (%s):%s to cache\n",
223                    e->e_dn, rw ? "w" : "r" ));
224 #endif
225         /* set cache mutex */
226         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
227
228         assert( e->e_private == NULL );
229
230         if( cache_entry_private_init(e) != 0 ) {
231                 /* free cache mutex */
232                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
233
234 #ifdef NEW_LOGGING
235                 LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
236                            "cache_add_entry_rw: add (%s):%ld private init failed!\n",
237                            e->e_dn, e->e_id ));
238 #else
239                 Debug( LDAP_DEBUG_ANY,
240                         "====> cache_add_entry( %ld ): \"%s\": private init failed!\n",
241                     e->e_id, e->e_dn, 0 );
242 #endif
243
244                 return( -1 );
245         }
246
247         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
248                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
249         {
250                 /* free cache mutex */
251                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
252
253 #ifdef NEW_LOGGING
254                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
255                            "cache_add_entry: (%s):%ld already in cache.\n",
256                            e->e_dn, e->e_id ));
257 #else
258                 Debug( LDAP_DEBUG_TRACE,
259                         "====> cache_add_entry( %ld ): \"%s\": already in dn cache\n",
260                     e->e_id, e->e_dn, 0 );
261 #endif
262
263                 cache_entry_private_destroy(e);
264
265                 return( 1 );
266         }
267
268         /* id tree */
269         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
270                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
271         {
272 #ifdef NEW_LOGGING
273                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
274                            "cache_add_entry: (%s):%ls already in cache.\n",
275                            e->e_dn, e->e_id ));
276 #else
277                 Debug( LDAP_DEBUG_ANY,
278                         "====> cache_add_entry( %ld ): \"%s\": already in id cache\n",
279                     e->e_id, e->e_dn, 0 );
280 #endif
281
282                 /* delete from dn tree inserted above */
283                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
284                         (AVL_CMP) entry_dn_cmp ) == NULL )
285                 {
286 #ifdef NEW_LOGGING
287                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
288                                    "cache_add_entry: can't delete (%s) from cache.\n",
289                                    e->e_dn ));
290 #else
291                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
292                             0, 0, 0 );
293 #endif
294                 }
295
296                 cache_entry_private_destroy(e);
297
298                 /* free cache mutex */
299                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
300                 return( -1 );
301         }
302
303         /* put the entry into 'CREATING' state */
304         /* will be marked after when entry is returned */
305         LEI(e)->lei_state = CACHE_ENTRY_CREATING;
306         LEI(e)->lei_refcnt = 1;
307
308         /* lru */
309         LRU_ADD( cache, e );
310         if ( ++cache->c_cursize > cache->c_maxsize ) {
311                 /*
312                  * find the lru entry not currently in use and delete it.
313                  * in case a lot of entries are in use, only look at the
314                  * first 10 on the tail of the list.
315                  */
316                 i = 0;
317                 while ( cache->c_lrutail != NULL &&
318                         LEI(cache->c_lrutail)->lei_refcnt != 0 &&
319                         i < 10 )
320                 {
321                         /* move this in-use entry to the front of the q */
322                         ee = cache->c_lrutail;
323                         LRU_DELETE( cache, ee );
324                         LRU_ADD( cache, ee );
325                         i++;
326                 }
327
328                 /*
329                  * found at least one to delete - try to get back under
330                  * the max cache size.
331                  */
332                 while ( cache->c_lrutail != NULL &&
333                         LEI(cache->c_lrutail)->lei_refcnt == 0 &&
334                         cache->c_cursize > cache->c_maxsize )
335                 {
336                         e = cache->c_lrutail;
337
338                         /* delete from cache and lru q */
339                         /* XXX do we need rc ? */
340                         rc = cache_delete_entry_internal( cache, e );
341                         cache_entry_private_destroy( e );
342                         entry_free( e );
343                 }
344         }
345
346         /* free cache mutex */
347         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
348         return( 0 );
349 }
350
351 /*
352  * cache_update_entry - update a LOCKED entry which has been deleted.
353  * returns:     0       entry has been created and locked
354  *              1       entry already existed
355  *              -1      something bad happened
356  */
357 int
358 cache_update_entry(
359     Cache       *cache,
360     Entry               *e
361 )
362 {
363         int     i, rc;
364         Entry   *ee;
365
366         /* set cache mutex */
367         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
368
369         assert( e->e_private );
370
371         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
372                 (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
373         {
374 #ifdef NEW_LOGGING
375                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
376                            "cache_update_entry: (%s):%ld already in dn cache\n",
377                            e->e_dn, e->e_id ));
378 #else
379                 Debug( LDAP_DEBUG_TRACE,
380                         "====> cache_update_entry( %ld ): \"%s\": already in dn cache\n",
381                     e->e_id, e->e_dn, 0 );
382 #endif
383
384                 /* free cache mutex */
385                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
386                 return( 1 );
387         }
388
389         /* id tree */
390         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
391                 (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
392         {
393 #ifdef NEW_LOGGING
394                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
395                            "cache_update_entry: (%s)%ld already in id cache\n",
396                            e->e_dn, e->e_id ));
397 #else
398                 Debug( LDAP_DEBUG_ANY,
399                         "====> cache_update_entry( %ld ): \"%s\": already in id cache\n",
400                     e->e_id, e->e_dn, 0 );
401 #endif
402
403                 /* delete from dn tree inserted above */
404                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
405                         (AVL_CMP) entry_dn_cmp ) == NULL )
406                 {
407 #ifdef NEW_LOGGING
408                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
409                                    "cache_update_entry: can't delete (%s)%ld from dn cache.\n",
410                                    e->e_dn, e->e_id ));
411 #else
412                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
413                             0, 0, 0 );
414 #endif
415                 }
416
417                 /* free cache mutex */
418                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
419                 return( -1 );
420         }
421
422         /* put the entry into 'CREATING' state */
423         /* will be marked after when entry is returned */
424         LEI(e)->lei_state = CACHE_ENTRY_CREATING;
425
426         /* lru */
427         LRU_ADD( cache, e );
428         if ( ++cache->c_cursize > cache->c_maxsize ) {
429                 /*
430                  * find the lru entry not currently in use and delete it.
431                  * in case a lot of entries are in use, only look at the
432                  * first 10 on the tail of the list.
433                  */
434                 i = 0;
435                 while ( cache->c_lrutail != NULL &&
436                         LEI(cache->c_lrutail)->lei_refcnt != 0 &&
437                         i < 10 )
438                 {
439                         /* move this in-use entry to the front of the q */
440                         ee = cache->c_lrutail;
441                         LRU_DELETE( cache, ee );
442                         LRU_ADD( cache, ee );
443                         i++;
444                 }
445
446                 /*
447                  * found at least one to delete - try to get back under
448                  * the max cache size.
449                  */
450                 while ( cache->c_lrutail != NULL &&
451                         LEI(cache->c_lrutail)->lei_refcnt == 0 &&
452                         cache->c_cursize > cache->c_maxsize )
453                 {
454                         e = cache->c_lrutail;
455
456                         /* delete from cache and lru q */
457                         /* XXX do we need rc ? */
458                         rc = cache_delete_entry_internal( cache, e );
459                         cache_entry_private_destroy( e );
460                         entry_free( e );
461                 }
462         }
463
464         /* free cache mutex */
465         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
466         return( 0 );
467 }
468
469 ID
470 cache_find_entry_ndn2id(
471         Backend         *be,
472     Cache       *cache,
473     struct berval       *ndn
474 )
475 {
476         Entry           e, *ep;
477         ID                      id;
478         int count = 0;
479
480         /* this function is always called with normalized DN */
481         e.e_nname = *ndn;
482
483 try_again:
484         /* set cache mutex */
485         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
486
487         if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
488                 (AVL_CMP) entry_dn_cmp )) != NULL )
489         {
490                 int state;
491                 count++;
492
493                 /*
494                  * ep now points to an unlocked entry
495                  * we do not need to lock the entry if we only
496                  * check the state, refcnt, LRU, and id.
497                  */
498                 assert( ep->e_private );
499
500                 /* save id */
501                 id = ep->e_id;
502                 state = LEI(ep)->lei_state;
503
504                 /*
505                  * entry is deleted or not fully created yet
506                  */
507                 if ( state != CACHE_ENTRY_READY ) {
508                         assert(state != CACHE_ENTRY_UNDEFINED);
509
510                         /* free cache mutex */
511                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
512
513 #ifdef NEW_LOGGING
514                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
515                                    "cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
516                                    ndn->bv_val, id, state ));
517 #else
518                         Debug(LDAP_DEBUG_TRACE,
519                                 "====> cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
520                                 ndn->bv_val, id, state);
521 #endif
522
523                         ldap_pvt_thread_yield();
524                         goto try_again;
525                 }
526
527                 /* lru */
528                 LRU_DELETE( cache, ep );
529                 LRU_ADD( cache, ep );
530                 
531                 /* free cache mutex */
532                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
533
534 #ifdef NEW_LOGGING
535                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
536                            "cache_find_entry_dn2id: (%s): %ld %d tries\n",
537                            ndn->bv_val, id, count ));
538 #else
539                 Debug(LDAP_DEBUG_TRACE,
540                         "====> cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
541                         ndn->bv_val, id, count);
542 #endif
543
544         } else {
545                 /* free cache mutex */
546                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
547                 id = NOID;
548         }
549
550         return( id );
551 }
552
553 /*
554  * cache_find_entry_id - find an entry in the cache, given id
555  */
556
557 Entry *
558 cache_find_entry_id(
559         Cache   *cache,
560         ID                              id,
561         int                             rw
562 )
563 {
564         Entry   e;
565         Entry   *ep;
566         int     count = 0;
567
568         e.e_id = id;
569
570 try_again:
571         /* set cache mutex */
572         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
573
574         if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
575                 (AVL_CMP) entry_id_cmp )) != NULL )
576         {
577                 int state;
578                 ID      ep_id;
579
580                 count++;
581
582                 assert( ep->e_private );
583
584                 ep_id = ep->e_id; 
585                 state = LEI(ep)->lei_state;
586
587                 /*
588                  * entry is deleted or not fully created yet
589                  */
590                 if ( state != CACHE_ENTRY_READY ) {
591                         assert(state != CACHE_ENTRY_UNDEFINED);
592
593                         /* free cache mutex */
594                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
595
596 #ifdef NEW_LOGGING
597                         LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
598                                    "cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
599                                    id, ep_id, state ));
600                                    
601 #else
602                         Debug(LDAP_DEBUG_TRACE,
603                                 "====> cache_find_entry_id( %ld ): %ld (not ready) %d\n",
604                                 id, ep_id, state);
605 #endif
606
607                         ldap_pvt_thread_yield();
608                         goto try_again;
609                 }
610
611                 /* lru */
612                 LRU_DELETE( cache, ep );
613                 LRU_ADD( cache, ep );
614                 
615                 LEI(ep)->lei_refcnt++;
616
617                 /* free cache mutex */
618                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
619
620 #ifdef NEW_LOGGING
621                 LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
622                            "cache_find_entry_id: %ld -> %s  found %d tries.\n",
623                            ep_id, ep->e_dn, count ));
624 #else
625                 Debug(LDAP_DEBUG_TRACE,
626                         "====> cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
627                         ep_id, ep->e_dn, count);
628 #endif
629
630                 return( ep );
631         }
632
633         /* free cache mutex */
634         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
635
636         return( NULL );
637 }
638
639 /*
640  * cache_delete_entry - delete the entry e from the cache.  the caller
641  * should have obtained e (increasing its ref count) via a call to one
642  * of the cache_find_* routines.  the caller should *not* call the
643  * cache_return_entry() routine prior to calling cache_delete_entry().
644  * it performs this function.
645  *
646  * returns:     0       e was deleted ok
647  *              1       e was not in the cache
648  *              -1      something bad happened
649  */
650 int
651 cache_delete_entry(
652     Cache       *cache,
653     Entry               *e
654 )
655 {
656         int     rc;
657
658         /* set cache mutex */
659         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
660
661         assert( e->e_private );
662
663 #ifdef NEW_LOGGING
664         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
665                    "cache_delete_entry: delete %ld.\n", e->e_id ));
666 #else
667         Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry( %ld )\n",
668                 e->e_id, 0, 0 );
669 #endif
670
671         rc = cache_delete_entry_internal( cache, e );
672
673         /* free cache mutex */
674         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
675         return( rc );
676 }
677
678 static int
679 cache_delete_entry_internal(
680     Cache       *cache,
681     Entry               *e
682 )
683 {
684         int rc = 0;     /* return code */
685
686         /* dn tree */
687         if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
688                 == NULL )
689         {
690                 rc = -1;
691         }
692
693         /* id tree */
694         if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
695                 == NULL )
696         {
697                 rc = -1;
698         }
699
700         if (rc != 0) {
701                 return rc;
702         }
703
704         /* lru */
705         LRU_DELETE( cache, e );
706         cache->c_cursize--;
707
708         /*
709          * flag entry to be freed later by a call to cache_return_entry()
710          */
711         LEI(e)->lei_state = CACHE_ENTRY_DELETED;
712
713         return( 0 );
714 }
715
716 void
717 cache_release_all( Cache *cache )
718 {
719         Entry *e;
720         int rc;
721
722         /* set cache mutex */
723         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
724
725 #ifdef NEW_LOGGING
726         LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
727                    "cache_release_all: enter\n" ));
728 #else
729         Debug( LDAP_DEBUG_TRACE, "====> cache_release_all\n", 0, 0, 0 );
730 #endif
731
732
733         while ( (e = cache->c_lrutail) != NULL && LEI(e)->lei_refcnt == 0 ) {
734                 /* delete from cache and lru q */
735                 /* XXX do we need rc ? */
736                 rc = cache_delete_entry_internal( cache, e );
737                 cache_entry_private_destroy( e );
738                 entry_free( e );
739         }
740
741         if ( cache->c_cursize ) {
742 #ifdef NEW_LOGGING
743                 LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
744                            "cache_release_all: Entry cache could not be emptied.\n" ));
745 #else
746                 Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
747 #endif
748         }
749
750         /* free cache mutex */
751         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
752 }
753
754 #ifdef LDAP_DEBUG
755 static void
756 lru_print( Cache *cache )
757 {
758         Entry   *e;
759
760         fprintf( stderr, "LRU queue (head to tail):\n" );
761         for ( e = cache->c_lruhead; e != NULL; e = LEI(e)->lei_lrunext ) {
762                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
763                         e->e_dn, e->e_id, LEI(e)->lei_refcnt );
764         }
765         fprintf( stderr, "LRU queue (tail to head):\n" );
766         for ( e = cache->c_lrutail; e != NULL; e = LEI(e)->lei_lruprev ) {
767                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
768                         e->e_dn, e->e_id, LEI(e)->lei_refcnt );
769         }
770 }
771 #endif