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