home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap / cache.c < prev    next >
C/C++ Source or Header  |  2000-07-29  |  16KB  |  667 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/libldap/cache.c,v 1.13.6.3 2000/07/29 01:53:08 kurt Exp $ */
  2. /*
  3.  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  4.  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  5.  */
  6. /*  Portions
  7.  *  Copyright (c) 1993 The Regents of the University of Michigan.
  8.  *  All rights reserved.
  9.  *
  10.  *  cache.c - local caching support for LDAP
  11.  */
  12.  
  13. #include "portable.h"
  14.  
  15. #include <stdio.h>
  16.  
  17. #include <ac/stdlib.h>
  18.  
  19. #include <ac/socket.h>
  20. #include <ac/string.h>
  21. #include <ac/time.h>
  22.  
  23. #include "ldap-int.h"
  24.  
  25. #ifndef LDAP_NOCACHE
  26.  
  27. static int        cache_hash LDAP_P(( BerElement *ber ));
  28. static LDAPMessage    *msg_dup LDAP_P(( LDAPMessage *msg ));
  29. static int        request_cmp LDAP_P(( BerElement    *req1, BerElement *req2 ));
  30. static int        chain_contains_dn LDAP_P(( LDAPMessage *msg, LDAP_CONST char *dn ));
  31. static ber_len_t    msg_size LDAP_P(( LDAPMessage *msg ));
  32. static void        check_cache_memused LDAP_P(( LDAPCache *lc ));
  33. static void        uncache_entry_or_req LDAP_P(( LDAP *ld, LDAP_CONST char *dn, ber_int_t msgid ));
  34.  
  35. #endif
  36.  
  37. int
  38. ldap_enable_cache( LDAP *ld, long timeout, ber_len_t maxmem )
  39. {
  40. #ifndef LDAP_NOCACHE
  41.     if ( ld->ld_cache == NULL ) {
  42.         if (( ld->ld_cache = (LDAPCache *)LDAP_MALLOC( sizeof( LDAPCache )))
  43.             == NULL ) {
  44.             ld->ld_errno = LDAP_NO_MEMORY;
  45.             return( -1 );
  46.         }
  47.         (void) memset( ld->ld_cache, '\0', sizeof( LDAPCache ));
  48.         ld->ld_cache->lc_memused = sizeof( LDAPCache );
  49.     }
  50.  
  51.     ld->ld_cache->lc_timeout = timeout;
  52.     ld->ld_cache->lc_maxmem = maxmem;
  53.     check_cache_memused( ld->ld_cache );
  54.     ld->ld_cache->lc_enabled = 1;
  55.     return( 0 );
  56. #else 
  57.     return( -1 );
  58. #endif
  59. }
  60.  
  61.  
  62. void
  63. ldap_disable_cache( LDAP *ld )
  64. {
  65. #ifndef LDAP_NOCACHE
  66.     if ( ld->ld_cache != NULL ) {
  67.         ld->ld_cache->lc_enabled = 0;
  68.     }
  69. #endif
  70. }
  71.  
  72.  
  73.  
  74. void
  75. ldap_set_cache_options( LDAP *ld, unsigned long opts )
  76. {
  77. #ifndef LDAP_NOCACHE
  78.     if ( ld->ld_cache != NULL ) {
  79.         ld->ld_cache->lc_options = opts;
  80.     }
  81. #endif
  82. }
  83.     
  84.  
  85. void
  86. ldap_destroy_cache( LDAP *ld )
  87. {
  88. #ifndef LDAP_NOCACHE
  89.     if ( ld->ld_cache != NULL ) {
  90.         ldap_flush_cache( ld );
  91.         LDAP_FREE( (char *)ld->ld_cache );
  92.         ld->ld_cache = NULL;
  93.     }
  94. #endif
  95. }
  96.  
  97.  
  98. void
  99. ldap_flush_cache( LDAP *ld )
  100. {
  101. #ifndef LDAP_NOCACHE
  102.     int        i;
  103.     LDAPMessage    *m, *next;
  104.  
  105.     Debug( LDAP_DEBUG_TRACE, "ldap_flush_cache\n", 0, 0, 0 );
  106.  
  107.     if ( ld->ld_cache != NULL ) {
  108.         /* delete all requests in the queue */
  109.         for ( m = ld->ld_cache->lc_requests; m != NULL; m = next ) {
  110.             next = m->lm_next;
  111.             ldap_msgfree( m );
  112.         }
  113.         ld->ld_cache->lc_requests = NULL;
  114.  
  115.         /* delete all messages in the cache */
  116.         for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) {
  117.             for ( m = ld->ld_cache->lc_buckets[ i ];
  118.                 m != NULL; m = next ) {
  119.                 next = m->lm_next;
  120.                 ldap_msgfree( m );
  121.             }
  122.             ld->ld_cache->lc_buckets[ i ] = NULL;
  123.         }
  124.         ld->ld_cache->lc_memused = sizeof( LDAPCache );
  125.     }
  126. #endif
  127. }
  128.  
  129.  
  130. void
  131. ldap_uncache_request( LDAP *ld, int msgid )
  132. {
  133. #ifndef LDAP_NOCACHE
  134.     Debug( LDAP_DEBUG_TRACE, "ldap_uncache_request %d ld_cache %lx\n",
  135.         msgid, (long) ld->ld_cache, 0 );
  136.  
  137.     uncache_entry_or_req( ld, NULL, msgid );
  138. #endif
  139. }
  140.  
  141.  
  142. void
  143. ldap_uncache_entry( LDAP *ld, LDAP_CONST char *dn )
  144. {
  145. #ifndef LDAP_NOCACHE
  146.     Debug( LDAP_DEBUG_TRACE, "ldap_uncache_entry %s ld_cache %lx\n",
  147.         dn, (long) ld->ld_cache, 0 );
  148.  
  149.     uncache_entry_or_req( ld, dn, 0 );
  150. #endif
  151. }
  152.  
  153.  
  154. #ifndef LDAP_NOCACHE
  155.  
  156. static void
  157. uncache_entry_or_req( LDAP *ld,
  158.     const char *dn,        /* if non-NULL, uncache entry */
  159.     ber_int_t msgid )        /* request to uncache (if dn == NULL) */
  160. {
  161.     int        i;
  162.     LDAPMessage    *m, *prev, *next;
  163.  
  164.     Debug( LDAP_DEBUG_TRACE,
  165.         "ldap_uncache_entry_or_req  dn %s  msgid %ld  ld_cache %lx\n",
  166.         dn, (long) msgid, (long) ld->ld_cache );
  167.  
  168.     if ( ld->ld_cache == NULL ) {
  169.         return;
  170.     }
  171.  
  172.     /* first check the request queue */
  173.     prev = NULL;
  174.     for ( m = ld->ld_cache->lc_requests; m != NULL; m = next ) {
  175.         next = m->lm_next;
  176.         if (( dn != NULL && chain_contains_dn( m, dn )) ||
  177.             ( dn == NULL && m->lm_msgid == msgid )) {
  178.             if ( prev == NULL ) {
  179.                 ld->ld_cache->lc_requests = next;
  180.             } else {
  181.                 prev->lm_next = next;
  182.             }
  183.             ld->ld_cache->lc_memused -= msg_size( m );
  184.             ldap_msgfree( m );
  185.         } else {
  186.             prev = m;
  187.         }
  188.     }
  189.  
  190.     /* now check the rest of the cache */
  191.     for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) {
  192.         prev = NULL;
  193.         for ( m = ld->ld_cache->lc_buckets[ i ]; m != NULL;
  194.             m = next ) {
  195.             next = m->lm_next;
  196.             if (( dn != NULL && chain_contains_dn( m, dn )) ||
  197.                 ( dn == NULL && m->lm_msgid == msgid )) {
  198.                 if ( prev == NULL ) {
  199.                     ld->ld_cache->lc_buckets[ i ] = next;
  200.                 } else {
  201.                     prev->lm_next = next;
  202.                 }
  203.                 ld->ld_cache->lc_memused -= msg_size( m );
  204.                 ldap_msgfree( m );
  205.             } else {
  206.                 prev = m;
  207.             }
  208.         }
  209.     }
  210. }
  211.  
  212. #endif
  213.  
  214. void
  215. ldap_add_request_to_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request )
  216. {
  217. #ifndef LDAP_NOCACHE
  218.     LDAPMessage    *new;
  219.     ber_len_t    len;
  220.  
  221.     Debug( LDAP_DEBUG_TRACE, "ldap_add_request_to_cache\n", 0, 0, 0 );
  222.  
  223.     ld->ld_errno = LDAP_SUCCESS;
  224.     if ( ld->ld_cache == NULL ||
  225.         ( ld->ld_cache->lc_enabled == 0 )) {
  226.         return;
  227.     }
  228.  
  229.     if (( new = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) ))
  230.         != NULL ) {
  231.         if (( new->lm_ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
  232.             LDAP_FREE( (char *)new );
  233.             return;
  234.         }
  235.         len = request->ber_ptr - request->ber_buf;
  236.         if (( new->lm_ber->ber_buf = (char *) ber_memalloc( (size_t)len ))
  237.             == NULL ) {
  238.             ber_free( new->lm_ber, 0 );
  239.             LDAP_FREE( (char *)new );
  240.             ld->ld_errno = LDAP_NO_MEMORY;
  241.             return;
  242.         }
  243.         AC_MEMCPY( new->lm_ber->ber_buf, request->ber_buf,
  244.             (size_t)len );
  245.         new->lm_ber->ber_ptr = new->lm_ber->ber_buf;
  246.         new->lm_ber->ber_end = new->lm_ber->ber_buf + len;
  247.         new->lm_msgid = ld->ld_msgid;
  248.         new->lm_msgtype = msgtype;;
  249.         new->lm_next = ld->ld_cache->lc_requests;
  250.         ld->ld_cache->lc_requests = new;
  251.     } else {
  252.         ld->ld_errno = LDAP_NO_MEMORY;
  253.     }
  254. #endif
  255. }
  256.  
  257.  
  258. void
  259. ldap_add_result_to_cache( LDAP *ld, LDAPMessage *result )
  260. {
  261. #ifndef LDAP_NOCACHE
  262.     LDAPMessage    *m, **mp, *req, *new, *prev;
  263.     int        err, keep;
  264.  
  265.     Debug( LDAP_DEBUG_TRACE, "ldap_add_result_to_cache: id %ld, type %ld\n", 
  266.         (long) result->lm_msgid, (long) result->lm_msgtype, 0 );
  267.  
  268.     if ( ld->ld_cache == NULL ||
  269.         ( ld->ld_cache->lc_enabled == 0 )) {
  270.         Debug( LDAP_DEBUG_TRACE, "artc: cache disabled\n", 0, 0, 0 );
  271.         return;
  272.     }
  273.  
  274.     if ( result->lm_msgtype != LDAP_RES_SEARCH_ENTRY &&
  275.         result->lm_msgtype != LDAP_RES_SEARCH_REFERENCE &&
  276.         result->lm_msgtype != LDAP_RES_SEARCH_RESULT &&
  277.         result->lm_msgtype != LDAP_RES_COMPARE ) {
  278.         /*
  279.          * only cache search and compare operations
  280.          */
  281.         Debug( LDAP_DEBUG_TRACE,
  282.             "artc: only caching search & compare operations\n", 0, 0, 0 );
  283.         return;
  284.     }
  285.  
  286.     /*
  287.      * if corresponding request is in the lc_requests list, add this
  288.      * result to it.  if this result completes the results for the
  289.      * request, add the request/result chain to the cache proper.
  290.      */
  291.     prev = NULL;
  292.     for ( m = ld->ld_cache->lc_requests; m != NULL; m = m->lm_next ) {
  293.         if ( m->lm_msgid == result->lm_msgid ) {
  294.             break;
  295.         }
  296.         prev = m;
  297.     }
  298.  
  299.     if ( m != NULL ) {    /* found request; add to end of chain */
  300.         req = m;
  301.         for ( ; m->lm_chain != NULL; m = m->lm_chain )
  302.             ;
  303.         if (( new = msg_dup( result )) != NULL ) {
  304.             new->lm_chain = NULL;
  305.             m->lm_chain = new;
  306.             Debug( LDAP_DEBUG_TRACE,
  307.                 "artc: result added to cache request chain\n",
  308.                 0, 0, 0 );
  309.         }
  310.         if ( result->lm_msgtype == LDAP_RES_SEARCH_RESULT ||
  311.             result->lm_msgtype == LDAP_RES_COMPARE ) {
  312.             /*
  313.              * this result completes the chain of results
  314.              * add to cache proper if appropriate
  315.              */
  316.             keep = 0;    /* pessimistic */
  317.             err = ldap_result2error( ld, result, 0 );
  318.             if ( err == LDAP_SUCCESS ||
  319.                 ( result->lm_msgtype == LDAP_RES_COMPARE &&
  320.                 ( err == LDAP_COMPARE_FALSE ||
  321.                 err == LDAP_COMPARE_TRUE ||
  322.                 err == LDAP_NO_SUCH_ATTRIBUTE ))) {
  323.                 keep = 1;
  324.             }
  325.  
  326.             if ( ld->ld_cache->lc_options == 0 ) {
  327.                 if ( err == LDAP_SIZELIMIT_EXCEEDED ) {
  328.                     keep = 1;
  329.                 }
  330.             } else if (( ld->ld_cache->lc_options &
  331.                 LDAP_CACHE_OPT_CACHEALLERRS ) != 0 ) {
  332.                 keep = 1;
  333.             }
  334.  
  335.             if ( prev == NULL ) {
  336.                 ld->ld_cache->lc_requests = req->lm_next;
  337.             } else {
  338.                 prev->lm_next = req->lm_next;
  339.             }
  340.  
  341.             if ( !keep ) {
  342.                 Debug( LDAP_DEBUG_TRACE,
  343.                     "artc: not caching result with error %d\n",
  344.                     err, 0, 0 );
  345.                 ldap_msgfree( req );
  346.             } else {
  347.                 mp = &ld->ld_cache->lc_buckets[
  348.                     cache_hash( req->lm_ber ) ];
  349.                 req->lm_next = *mp;
  350.                 *mp = req;
  351.                 req->lm_time = (long) time( NULL );
  352.                 ld->ld_cache->lc_memused += msg_size( req );
  353.                 check_cache_memused( ld->ld_cache );
  354.                 Debug( LDAP_DEBUG_TRACE,
  355.                     "artc: cached result with error %d\n",
  356.                     err, 0, 0 );
  357.             }
  358.         }
  359.     } else {
  360.         Debug( LDAP_DEBUG_TRACE, "artc: msgid not in request list\n",
  361.             0, 0, 0 );
  362.     }
  363. #endif
  364. }
  365.  
  366.  
  367. /*
  368.  * look in the cache for this request
  369.  * return 0 if found, -1 if not
  370.  * if found, the corresponding result messages are added to the incoming
  371.  * queue with the correct (new) msgid so that subsequent ldap_result calls
  372.  * will find them.
  373.  */
  374. int
  375. ldap_check_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request )
  376. {
  377. #ifndef LDAP_NOCACHE
  378.     LDAPMessage    *m, *new, *prev, *next;
  379.     BerElement    reqber;
  380.     int        first, hash;
  381.     time_t    c_time;
  382.  
  383.     Debug( LDAP_DEBUG_TRACE, "ldap_check_cache\n", 0, 0, 0 );
  384.  
  385.     if ( ld->ld_cache == NULL ||
  386.         ( ld->ld_cache->lc_enabled == 0 )) {
  387.         return( -1 );
  388.     }
  389.  
  390.     reqber.ber_valid = LBER_VALID_BERELEMENT;
  391.     reqber.ber_buf = reqber.ber_ptr = request->ber_buf;
  392.     reqber.ber_end = request->ber_ptr;
  393.  
  394.     c_time = time( NULL );
  395.  
  396.     prev = NULL;
  397.     hash = cache_hash( &reqber );
  398.     for ( m = ld->ld_cache->lc_buckets[ hash ]; m != NULL; m = next ) {
  399.         Debug( LDAP_DEBUG_TRACE,"cc: examining id %ld,type %ld\n",
  400.             (long) m->lm_msgid, (long) m->lm_msgtype, 0 );
  401.         if ( difftime(c_time, m->lm_time) > ld->ld_cache->lc_timeout ) {
  402.             /* delete expired message */
  403.             next = m->lm_next;
  404.             if ( prev == NULL ) {
  405.                 ld->ld_cache->lc_buckets[ hash ] = next;
  406.             } else {
  407.                 prev->lm_next = next;
  408.             }
  409.             Debug( LDAP_DEBUG_TRACE, "cc: expired id %d\n",
  410.                 m->lm_msgid, 0, 0 );
  411.             ld->ld_cache->lc_memused -= msg_size( m );
  412.             ldap_msgfree( m );
  413.         } else {
  414.             if ( m->lm_msgtype == (int)msgtype &&
  415.             request_cmp( m->lm_ber, &reqber ) == 0 ) {
  416.                 break;
  417.             }
  418.             next = m->lm_next;
  419.             prev = m;
  420.         }
  421.     }
  422.  
  423.     if ( m == NULL ) {
  424.         return( -1 );
  425.     }
  426.  
  427.     /*
  428.      * add duplicates of responses to incoming queue
  429.      */
  430.     first = 1;
  431.     for ( m = m->lm_chain; m != NULL; m = m->lm_chain ) {
  432.         if (( new = msg_dup( m )) == NULL ) {
  433.             return( -1 );
  434.         }
  435.  
  436.         new->lm_msgid = ld->ld_msgid;
  437.         new->lm_chain = NULL;
  438.         if ( first ) {
  439.             new->lm_next = ld->ld_responses;
  440.             ld->ld_responses = new;
  441.             first = 0;
  442.         } else {
  443.             prev->lm_chain = new;
  444.         }
  445.         prev = new;
  446.         Debug( LDAP_DEBUG_TRACE, "cc: added type %ld\n",
  447.             (long) new->lm_msgtype, 0, 0 );
  448.     }
  449.  
  450.     Debug( LDAP_DEBUG_TRACE, "cc: result returned from cache\n", 0, 0, 0 );
  451.     return( 0 );
  452. #else
  453.     return( -1 );
  454. #endif
  455. }
  456.  
  457. #ifndef LDAP_NOCACHE
  458.  
  459. static int
  460. cache_hash( BerElement *ber )
  461. {
  462.     BerElement    bercpy;
  463.     ber_len_t    len;
  464.  
  465.     /*
  466.          * just take the length of the packet and mod with # of buckets
  467.      */
  468.     bercpy = *ber;
  469.     if ( ber_skip_tag( &bercpy, &len ) == LBER_ERROR
  470.         || ber_scanf( &bercpy, "x" ) == LBER_ERROR ) {
  471.         len = 0;    /* punt: just return zero */
  472.     } else {
  473.         len = bercpy.ber_end - bercpy.ber_ptr;
  474.     }
  475.  
  476.     Debug( LDAP_DEBUG_TRACE, "cache_hash: len is %ld, returning %ld\n",
  477.         len, len % LDAP_CACHE_BUCKETS, 0 );
  478.     return( (int) ( len % LDAP_CACHE_BUCKETS ));
  479. }
  480.  
  481.  
  482. static LDAPMessage *
  483. msg_dup( LDAPMessage *msg )
  484. {
  485.     LDAPMessage    *new;
  486.     ber_len_t    len;
  487.  
  488.     if (( new = (LDAPMessage *)LDAP_MALLOC( sizeof(LDAPMessage))) != NULL ) {
  489.         *new = *msg;    /* struct copy */
  490.         if (( new->lm_ber = ber_dup( msg->lm_ber )) == NULL ) {
  491.             LDAP_FREE( (char *)new );
  492.             return( NULL );
  493.         }
  494.         len = msg->lm_ber->ber_end - msg->lm_ber->ber_buf;
  495.         if (( new->lm_ber->ber_buf = (char *) ber_memalloc(
  496.             (size_t)len )) == NULL ) {
  497.             ber_free( new->lm_ber, 0 );
  498.             LDAP_FREE( (char *)new );
  499.             return( NULL );
  500.         }
  501.         AC_MEMCPY( new->lm_ber->ber_buf, msg->lm_ber->ber_buf,
  502.             (size_t)len );
  503.         new->lm_ber->ber_ptr = new->lm_ber->ber_buf +
  504.             ( msg->lm_ber->ber_ptr - msg->lm_ber->ber_buf );
  505.         new->lm_ber->ber_end = new->lm_ber->ber_buf + len;
  506.     }
  507.  
  508.     return( new );
  509. }
  510.  
  511.  
  512. static int
  513. request_cmp( BerElement *req1, BerElement *req2 )
  514. {
  515.     ber_len_t    len;
  516.     BerElement    r1, r2;
  517.  
  518.     r1 = *req1;    /* struct copies */
  519.     r2 = *req2;
  520.  
  521.     /*
  522.      * skip the enclosing tags (sequence markers) and the msg ids
  523.      */
  524.     if ( ber_skip_tag( &r1, &len ) == LBER_ERROR || ber_scanf( &r1, "x" )
  525.         == LBER_ERROR ) {
  526.         return( -1 );
  527.     }
  528.     if ( ber_skip_tag( &r2, &len ) == LBER_ERROR || ber_scanf( &r2, "x" ) 
  529.         == LBER_ERROR ) {
  530.         return( -1 );
  531.     }
  532.  
  533.     /*
  534.      * check remaining length and bytes if necessary
  535.      */
  536.     if (( len = r1.ber_end - r1.ber_ptr ) !=
  537.         (ber_len_t) (r2.ber_end - r2.ber_ptr) )
  538.     {
  539.         return( -1 );    /* different lengths */
  540.     }
  541.     return( memcmp( r1.ber_ptr, r2.ber_ptr, (size_t)len ));
  542. }    
  543.  
  544.  
  545. static int
  546. chain_contains_dn( LDAPMessage *msg, const char *dn )
  547. {
  548.     LDAPMessage    *m;
  549.     BerElement    ber;
  550.     ber_int_t        msgid;
  551.     char        *s;
  552.     int        rc;
  553.  
  554.  
  555.     /*
  556.      * first check the base or dn of the request
  557.      */
  558.     ber = *msg->lm_ber;    /* struct copy */
  559.     if ( ber_scanf( &ber, "{i{a" /*}}*/, &msgid, &s ) != LBER_ERROR ) {
  560.         rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0;
  561.         LDAP_FREE( s );
  562.         if ( rc != 0 ) {
  563.         return( rc );
  564.         }
  565.     }
  566.  
  567.     if ( msg->lm_msgtype == LDAP_REQ_COMPARE ) {
  568.         return( 0 );
  569.     }
  570.  
  571.     /*
  572.      * now check the dn of each search result
  573.      */
  574.     rc = 0;
  575.     for ( m = msg->lm_chain; m != NULL && rc == 0 ; m = m->lm_chain ) {
  576.         if ( m->lm_msgtype != LDAP_RES_SEARCH_ENTRY ) {
  577.             continue;
  578.         }
  579.         ber = *m->lm_ber;    /* struct copy */
  580.         if ( ber_scanf( &ber, "{a" /*}*/, &s ) != LBER_ERROR ) {
  581.             rc = ( strcasecmp( dn, s ) == 0 ) ? 1 : 0;
  582.             LDAP_FREE( s );
  583.         }
  584.     }
  585.  
  586.     return( rc );
  587. }
  588.  
  589.  
  590. static ber_len_t
  591. msg_size( LDAPMessage *msg )
  592. {
  593.     LDAPMessage    *m;
  594.     ber_len_t    size;
  595.  
  596.     size = 0;
  597.     for ( m = msg; m != NULL; m = m->lm_chain ) {
  598.         size += ( sizeof( LDAPMessage ) + m->lm_ber->ber_end -
  599.             m->lm_ber->ber_buf );
  600.     }
  601.  
  602.     return( size );
  603. }
  604.  
  605.  
  606. #define THRESHOLD_FACTOR    3 / 4
  607. #define SIZE_FACTOR        2 / 3
  608.  
  609. static void
  610. check_cache_memused( LDAPCache *lc )
  611. {
  612. /*
  613.  * this routine is called to check if the cache is too big (lc_maxmem >
  614.  * minimum cache size and lc_memused > lc_maxmem).  If too big, it reduces
  615.  * the cache size to < SIZE_FACTOR * lc_maxmem. The algorithm is as follows:
  616.  *    remove_threshold = lc_timeout seconds;
  617.  *    do {
  618.  *        remove everything older than remove_threshold seconds;
  619.  *        remove_threshold = remove_threshold * THRESHOLD_FACTOR;
  620.  *    } while ( cache size is > SIZE_FACTOR * lc_maxmem )
  621.  */
  622.     int        i;
  623.     unsigned long    remove_threshold;
  624.     time_t c_time;
  625.     LDAPMessage    *m, *prev, *next;
  626.  
  627.     Debug( LDAP_DEBUG_TRACE, "check_cache_memused: %ld bytes in use (%ld max)\n",
  628.         lc->lc_memused, lc->lc_maxmem, 0 );
  629.  
  630.     if ( (unsigned) lc->lc_maxmem <= sizeof( LDAPCache )
  631.         || lc->lc_memused <= lc->lc_maxmem * SIZE_FACTOR ) {
  632.         return;
  633.     }
  634.  
  635.     remove_threshold = lc->lc_timeout;
  636.     while ( lc->lc_memused > lc->lc_maxmem * SIZE_FACTOR ) {
  637.         c_time = time( NULL );
  638.         for ( i = 0; i < LDAP_CACHE_BUCKETS; ++i ) {
  639.             prev = NULL;
  640.             for ( m = lc->lc_buckets[ i ]; m != NULL;
  641.                 m = next ) {
  642.                 next = m->lm_next;
  643.                 if ( difftime(c_time, m->lm_time) > remove_threshold) {
  644.                     if ( prev == NULL ) {
  645.                         lc->lc_buckets[ i ] = next;
  646.                     } else {
  647.                         prev->lm_next = next;
  648.                     }
  649.                     lc->lc_memused -= msg_size( m );
  650.                     Debug( LDAP_DEBUG_TRACE,
  651.                         "ccm: removed %d\n",
  652.                         m->lm_msgid, 0, 0 );
  653.                     ldap_msgfree( m );
  654.                 } else {
  655.                     prev = m;
  656.                 }
  657.             }
  658.         }
  659.         remove_threshold *= THRESHOLD_FACTOR;
  660.     }
  661.  
  662.     Debug( LDAP_DEBUG_TRACE, "ccm: reduced usage to %ld bytes\n",
  663.         lc->lc_memused, 0, 0 );
  664. }
  665.  
  666. #endif /* !NO_CACHE */
  667.