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