]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/cache.c
b23ca2a7761e096ac1fe111bc8349137df0fb49a
[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         struct ldbm_entry_info *lei;
93
94 #ifdef LDAP_DEBUG
95         assert( e->e_private == NULL );
96 #endif
97
98         if( e->e_private != NULL ) {
99                 /* this should never happen */
100                 return 1;
101         }
102
103         e->e_private = ch_calloc(1, sizeof(struct ldbm_entry_info));
104
105         if( cache_entry_rdwr_init( e ) != 0 ) {
106                 free( LEI(e) );
107                 e->e_private = NULL;
108                 return 1;
109         } 
110
111         return 0;
112 }
113
114 static int
115 cache_entry_private_destroy( Entry*e )
116 {
117         struct ldbm_entry_info *lei;
118
119 #ifdef LDAP_DEBUG
120         assert( e->e_private );
121 #endif
122
123         cache_entry_rdwr_destroy( e );
124
125         free( e->e_private );
126         e->e_private = NULL;
127         return 0;
128 }
129
130 void
131 cache_return_entry_rw( struct cache *cache, Entry *e, int rw )
132 {
133         /* set cache mutex */
134         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
135
136 #ifdef LDAP_DEBUG
137         assert( e->e_private );
138 #endif
139
140         cache_entry_rdwr_unlock(e, rw);
141
142         LEI(e)->lei_refcnt--;
143
144         if ( LEI(e)->lei_state == CACHE_ENTRY_CREATING ) {
145                 Debug( LDAP_DEBUG_TRACE,
146                         "====> cache_return_entry_%s( %ld ): created (%d)\n",
147                         rw ? "w" : "r", e->e_id, LEI(e)->lei_refcnt );
148
149                 LEI(e)->lei_state = CACHE_ENTRY_READY;
150
151         } else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED ) {
152                 if( LEI(e)->lei_refcnt > 0 ) {
153                         Debug( LDAP_DEBUG_TRACE,
154                                 "====> cache_return_entry_%s( %ld ): delete pending (%d)\n",
155                                 rw ? "w" : "r", e->e_id, LEI(e)->lei_refcnt );
156
157                 } else {
158                         Debug( LDAP_DEBUG_TRACE,
159                                 "====> cache_return_entry_%s( %ld ): deleted (%d)\n",
160                                 rw ? "w" : "r", e->e_id, LEI(e)->lei_refcnt );
161
162                         cache_entry_private_destroy( e );
163                         entry_free( e );
164                 }
165
166         } else {
167                 Debug( LDAP_DEBUG_TRACE,
168                         "====> cache_return_entry_%s( %ld ): returned (%d)\n",
169                         rw ? "w" : "r", e->e_id, LEI(e)->lei_refcnt);
170         }
171
172
173         /* free cache mutex */
174         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
175 }
176
177 #define LRU_DELETE( cache, e ) { \
178         if ( LEI(e)->lei_lruprev != NULL ) { \
179                 LEI(LEI(e)->lei_lruprev)->lei_lrunext = LEI(e)->lei_lrunext; \
180         } else { \
181                 cache->c_lruhead = LEI(e)->lei_lrunext; \
182         } \
183         if ( LEI(e)->lei_lrunext != NULL ) { \
184                 LEI(LEI(e)->lei_lrunext)->lei_lruprev = LEI(e)->lei_lruprev; \
185         } else { \
186                 cache->c_lrutail = LEI(e)->lei_lruprev; \
187         } \
188 }
189
190 #define LRU_ADD( cache, e ) { \
191         LEI(e)->lei_lrunext = cache->c_lruhead; \
192         if ( LEI(e)->lei_lrunext != NULL ) { \
193                 LEI(LEI(e)->lei_lrunext)->lei_lruprev = e; \
194         } \
195         cache->c_lruhead = e; \
196         LEI(e)->lei_lruprev = NULL; \
197         if ( cache->c_lrutail == NULL ) { \
198                 cache->c_lrutail = e; \
199         } \
200 }
201
202 /*
203  * cache_add_entry_rw - create and lock an entry in the cache
204  * returns:     0       entry has been created and locked
205  *              1       entry already existed
206  *              -1      something bad happened
207  */
208 int
209 cache_add_entry_rw(
210     struct cache        *cache,
211     Entry               *e,
212         int             rw
213 )
214 {
215         int     i, rc;
216         Entry   *ee;
217
218         /* set cache mutex */
219         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
220
221 #ifdef LDAP_DEBUG
222         assert( e->e_private == NULL );
223 #endif
224
225         if( cache_entry_private_init(e) != 0 ) {
226                 Debug( LDAP_DEBUG_ANY,
227                         "====> cache_add_entry( %ld ): \"%s\": private init failed!\n",
228                     e->e_id, e->e_dn, 0 );
229                 return( -1 );
230         }
231
232         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
233                 entry_dn_cmp, avl_dup_error ) != 0 )
234         {
235                 Debug( LDAP_DEBUG_TRACE,
236                         "====> cache_add_entry( %ld ): \"%s\": already in dn cache\n",
237                     e->e_id, e->e_dn, 0 );
238
239                 cache_entry_private_destroy(e);
240
241                 /* free cache mutex */
242                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
243                 return( 1 );
244         }
245
246         /* id tree */
247         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
248                 entry_id_cmp, avl_dup_error ) != 0 )
249         {
250                 Debug( LDAP_DEBUG_ANY,
251                         "====> cache_add_entry( %ld ): \"%s\": already in id cache\n",
252                     e->e_id, e->e_dn, 0 );
253
254
255                 /* delete from dn tree inserted above */
256                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
257                         entry_dn_cmp ) == NULL )
258                 {
259                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
260                             0, 0, 0 );
261                 }
262
263                 cache_entry_private_destroy(e);
264
265                 /* free cache mutex */
266                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
267                 return( -1 );
268         }
269
270         cache_entry_rdwr_lock( e, rw );
271
272         /* put the entry into 'CREATING' state */
273         /* will be marked after when entry is returned */
274         LEI(e)->lei_state = CACHE_ENTRY_CREATING;
275         LEI(e)->lei_refcnt = 1;
276
277         /* lru */
278         LRU_ADD( cache, e );
279         if ( ++cache->c_cursize > cache->c_maxsize ) {
280                 /*
281                  * find the lru entry not currently in use and delete it.
282                  * in case a lot of entries are in use, only look at the
283                  * first 10 on the tail of the list.
284                  */
285                 i = 0;
286                 while ( cache->c_lrutail != NULL &&
287                         LEI(cache->c_lrutail)->lei_refcnt != 0 &&
288                         i < 10 )
289                 {
290                         /* move this in-use entry to the front of the q */
291                         ee = cache->c_lrutail;
292                         LRU_DELETE( cache, ee );
293                         LRU_ADD( cache, ee );
294                         i++;
295                 }
296
297                 /*
298                  * found at least one to delete - try to get back under
299                  * the max cache size.
300                  */
301                 while ( cache->c_lrutail != NULL &&
302                         LEI(cache->c_lrutail)->lei_refcnt == 0 &&
303                         cache->c_cursize > cache->c_maxsize )
304                 {
305                         e = cache->c_lrutail;
306
307                         /* delete from cache and lru q */
308                         rc = cache_delete_entry_internal( cache, e );
309                         cache_entry_private_destroy( e );
310                         entry_free( e );
311                 }
312         }
313
314         /* free cache mutex */
315         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
316         return( 0 );
317 }
318
319 /*
320  * cache_update_entry - update a LOCKED entry which has been deleted.
321  * returns:     0       entry has been created and locked
322  *              1       entry already existed
323  *              -1      something bad happened
324  */
325 int
326 cache_update_entry(
327     struct cache        *cache,
328     Entry               *e
329 )
330 {
331         int     i, rc;
332         Entry   *ee;
333
334         /* set cache mutex */
335         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
336
337 #ifdef LDAP_DEBUG
338         assert( e->e_private );
339 #endif
340
341         if ( avl_insert( &cache->c_dntree, (caddr_t) e,
342                 entry_dn_cmp, avl_dup_error ) != 0 )
343         {
344                 Debug( LDAP_DEBUG_TRACE,
345                         "====> cache_update_entry( %ld ): \"%s\": already in dn cache\n",
346                     e->e_id, e->e_dn, 0 );
347
348                 /* free cache mutex */
349                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
350                 return( 1 );
351         }
352
353         /* id tree */
354         if ( avl_insert( &cache->c_idtree, (caddr_t) e,
355                 entry_id_cmp, avl_dup_error ) != 0 )
356         {
357                 Debug( LDAP_DEBUG_ANY,
358                         "====> cache_update_entry( %ld ): \"%s\": already in id cache\n",
359                     e->e_id, e->e_dn, 0 );
360
361                 /* delete from dn tree inserted above */
362                 if ( avl_delete( &cache->c_dntree, (caddr_t) e,
363                         entry_dn_cmp ) == NULL )
364                 {
365                         Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
366                             0, 0, 0 );
367                 }
368
369                 /* free cache mutex */
370                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
371                 return( -1 );
372         }
373
374
375         /* put the entry into 'CREATING' state */
376         /* will be marked after when entry is returned */
377         LEI(e)->lei_state = CACHE_ENTRY_CREATING;
378
379         /* lru */
380         LRU_ADD( cache, e );
381         if ( ++cache->c_cursize > cache->c_maxsize ) {
382                 /*
383                  * find the lru entry not currently in use and delete it.
384                  * in case a lot of entries are in use, only look at the
385                  * first 10 on the tail of the list.
386                  */
387                 i = 0;
388                 while ( cache->c_lrutail != NULL &&
389                         LEI(cache->c_lrutail)->lei_refcnt != 0 &&
390                         i < 10 )
391                 {
392                         /* move this in-use entry to the front of the q */
393                         ee = cache->c_lrutail;
394                         LRU_DELETE( cache, ee );
395                         LRU_ADD( cache, ee );
396                         i++;
397                 }
398
399                 /*
400                  * found at least one to delete - try to get back under
401                  * the max cache size.
402                  */
403                 while ( cache->c_lrutail != NULL &&
404                         LEI(cache->c_lrutail)->lei_refcnt == 0 &&
405                         cache->c_cursize > cache->c_maxsize )
406                 {
407                         e = cache->c_lrutail;
408
409                         /* delete from cache and lru q */
410                         rc = cache_delete_entry_internal( cache, e );
411                         cache_entry_private_destroy( e );
412                         entry_free( e );
413                 }
414         }
415
416         /* free cache mutex */
417         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
418         return( 0 );
419 }
420
421 /*
422  * cache_find_entry_dn2id - find an entry in the cache, given dn
423  */
424
425 ID
426 cache_find_entry_dn2id(
427         Backend         *be,
428     struct cache        *cache,
429     char                *dn
430 )
431 {
432         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
433         Entry           e, *ep;
434         ID                      id;
435
436         /* set cache mutex */
437         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
438
439         e.e_dn = dn;
440         e.e_ndn = dn_normalize_case( ch_strdup( dn ) );
441
442         if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
443                 entry_dn_cmp )) != NULL )
444         {
445                 /*
446                  * ep now points to an unlocked entry
447                  * we do not need to lock the entry if we only
448                  * check the state, refcnt, LRU, and id.
449                  */
450                 free(e.e_ndn);
451
452 #ifdef LDAP_DEBUG
453                 assert( ep->e_private );
454 #endif
455                 /*
456                  * entry is deleted or not fully created yet
457                  */
458                 if ( LEI(ep)->lei_state != CACHE_ENTRY_READY ) {
459 #ifdef LDAP_DEBUG
460                         assert(LEI(ep)->lei_state != CACHE_ENTRY_UNDEFINED);
461 #endif
462                         Debug(LDAP_DEBUG_TRACE,
463                                 "====> cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
464                                 dn, ep->e_id, LEI(ep)->lei_state);
465
466                         /* free cache mutex */
467                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
468                         return( NOID );
469                 }
470
471                 Debug(LDAP_DEBUG_TRACE,
472                         "====> cache_find_entry_dn2id(\"%s\"): %ld\n",
473                         dn, ep->e_id, 0);
474
475                 /* lru */
476                 LRU_DELETE( cache, ep );
477                 LRU_ADD( cache, ep );
478                 
479                 /* save id */
480                 id = ep->e_id;
481
482                 /* free cache mutex */
483                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
484
485                 return( id );
486         }
487
488         free(e.e_ndn);
489
490         /* free cache mutex */
491         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
492
493         return( NOID );
494 }
495
496 /*
497  * cache_find_entry_id - find an entry in the cache, given id
498  */
499
500 Entry *
501 cache_find_entry_id(
502         struct cache    *cache,
503         ID                              id,
504         int                             rw
505 )
506 {
507         Entry   e;
508         Entry   *ep;
509
510         e.e_id = id;
511
512 try_again:
513         /* set cache mutex */
514         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
515
516         if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
517                 entry_id_cmp )) != NULL )
518         {
519 #ifdef LDAP_DEBUG
520                 assert( ep->e_private );
521 #endif
522                 /*
523                  * entry is deleted or not fully created yet
524                  */
525                 if ( LEI(ep)->lei_state != CACHE_ENTRY_READY ) {
526 #ifdef LDAP_DEBUG
527                         assert(LEI(ep)->lei_state != CACHE_ENTRY_UNDEFINED);
528 #endif
529                         Debug(LDAP_DEBUG_TRACE,
530                                 "====> cache_find_entry_id( %ld ): %ld (not ready) %d\n",
531                                 id, ep->e_id, LEI(ep)->lei_state);
532
533                         /* free cache mutex */
534                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
535                         return( NULL );
536                 }
537
538                 Debug(LDAP_DEBUG_TRACE,
539                         "====> cache_find_entry_id( %ld, %s ) \"%s\" (found)\n",
540                         id, rw ? "w" : "r", ep->e_dn);
541
542                 /* acquire reader lock */
543                 if ( cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
544                         /* could not acquire entry lock...
545                          * owner cannot free as we have the cache locked.
546                          * so, unlock the cache, yield, and try again.
547                          */
548
549                         /* free cache mutex */
550                         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
551                         ldap_pvt_thread_yield();
552                         goto try_again;
553                 }
554
555                 /* lru */
556                 LRU_DELETE( cache, ep );
557                 LRU_ADD( cache, ep );
558                 
559                 LEI(ep)->lei_refcnt++;
560
561                 /* free cache mutex */
562                 ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
563
564                 return( ep );
565         }
566
567         /* free cache mutex */
568         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
569
570         return( NULL );
571 }
572
573 /*
574  * cache_delete_entry - delete the entry e from the cache.  the caller
575  * should have obtained e (increasing its ref count) via a call to one
576  * of the cache_find_* routines.  the caller should *not* call the
577  * cache_return_entry() routine prior to calling cache_delete_entry().
578  * it performs this function.
579  *
580  * returns:     0       e was deleted ok
581  *              1       e was not in the cache
582  *              -1      something bad happened
583  */
584 int
585 cache_delete_entry(
586     struct cache        *cache,
587     Entry               *e
588 )
589 {
590         int     rc;
591
592         /* set cache mutex */
593         ldap_pvt_thread_mutex_lock( &cache->c_mutex );
594
595 #ifdef LDAP_DEBUG
596         assert( e->e_private );
597 #endif
598
599         Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry( %ld )\n",
600                 e->e_id, 0, 0 );
601
602         rc = cache_delete_entry_internal( cache, e );
603
604         /* free cache mutex */
605         ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
606         return( rc );
607 }
608
609 static int
610 cache_delete_entry_internal(
611     struct cache        *cache,
612     Entry               *e
613 )
614 {
615         int rc = 0;     /* return code */
616
617         /* dn tree */
618         if ( avl_delete( &cache->c_dntree, (caddr_t) e, entry_dn_cmp )
619                 == NULL )
620         {
621                 rc = -1;
622         }
623
624         /* id tree */
625         if ( avl_delete( &cache->c_idtree, (caddr_t) e, entry_id_cmp )
626                 == NULL )
627         {
628                 rc = -1;
629         }
630
631         if (rc != 0) {
632                 return rc;
633         }
634
635         /* lru */
636         LRU_DELETE( cache, e );
637         cache->c_cursize--;
638
639         /*
640          * flag entry to be freed later by a call to cache_return_entry()
641          */
642         LEI(e)->lei_state = CACHE_ENTRY_DELETED;
643
644         return( 0 );
645 }
646
647 #ifdef LDAP_DEBUG
648
649 static void
650 lru_print( struct cache *cache )
651 {
652         Entry   *e;
653
654         fprintf( stderr, "LRU queue (head to tail):\n" );
655         for ( e = cache->c_lruhead; e != NULL; e = LEI(e)->lei_lrunext ) {
656                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
657                         e->e_dn, e->e_id, LEI(e)->lei_refcnt );
658         }
659         fprintf( stderr, "LRU queue (tail to head):\n" );
660         for ( e = cache->c_lrutail; e != NULL; e = LEI(e)->lei_lruprev ) {
661                 fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
662                         e->e_dn, e->e_id, LEI(e)->lei_refcnt );
663         }
664 }
665
666 #endif
667