]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldbm/cache.c
Import resetting of c_dn/c_cdn after anonymous bind.
[openldap] / servers / slapd / back-ldbm / cache.c
index 49fafb6975da2512d64a8bc545abb392a1f6004b..a9c31cc3eb68bff427e6c6193ef39255228d6610 100644 (file)
@@ -1,14 +1,19 @@
 /* cache.c - routines to maintain an in-core cache of entries */
 
+#include "portable.h"
+
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
 #include "slap.h"
+
 #include "back-ldbm.h"
 
-static int     cache_delete_entry_internal();
+static int     cache_delete_entry_internal(struct cache *cache, Entry *e);
 #ifdef LDAP_DEBUG
-static void    lru_print();
+static void    lru_print(struct cache *cache);
 #endif
 
 /*
@@ -31,7 +36,8 @@ cache_entry_cmp( Entry *e1, Entry *e2 )
 static int
 cache_entrydn_cmp( Entry *e1, Entry *e2 )
 {
-       return( strcasecmp( e1->e_dn, e2->e_dn ) );
+       /* compare their normalized UPPERCASED dn's */
+       return( strcmp( e1->e_ndn, e2->e_ndn ) );
 }
 
 static int
@@ -52,7 +58,7 @@ cache_set_state( struct cache *cache, Entry *e, int state )
        pthread_mutex_unlock( &cache->c_mutex );
 }
 
-void
+static void
 cache_return_entry( struct cache *cache, Entry *e )
 {
        /* set cache mutex */
@@ -66,6 +72,28 @@ cache_return_entry( struct cache *cache, Entry *e )
        pthread_mutex_unlock( &cache->c_mutex );
 }
 
+static void
+cache_return_entry_rw( struct cache *cache, Entry *e, int rw )
+{
+       Debug( LDAP_DEBUG_TRACE, "====> cache_return_entry_%s\n",
+               rw ? "w" : "r", 0, 0);
+       entry_rdwr_unlock(e, rw);;
+       cache_return_entry(cache, e);
+}
+
+void
+cache_return_entry_r( struct cache *cache, Entry *e )
+{
+       cache_return_entry_rw(cache, e, 0);
+}
+
+void
+cache_return_entry_w( struct cache *cache, Entry *e )
+{
+       cache_return_entry_rw(cache, e, 1);
+}
+
+
 #define LRU_DELETE( cache, e ) { \
        if ( e->e_lruprev != NULL ) { \
                e->e_lruprev->e_lrunext = e->e_lrunext; \
@@ -110,11 +138,12 @@ cache_add_entry_lock(
        /* set cache mutex */
        pthread_mutex_lock( &cache->c_mutex );
 
-       if ( avl_insert( &cache->c_dntree, e, cache_entrydn_cmp, avl_dup_error )
-           != 0 ) {
+       if ( avl_insert( &cache->c_dntree, (caddr_t) e,
+               cache_entrydn_cmp, avl_dup_error ) != 0 )
+       {
                Debug( LDAP_DEBUG_TRACE,
-                   "entry %20s id %d already in dn cache\n", e->e_dn,
-                   e->e_id, 0 );
+                       "====> cache_add_entry lock: entry %20s id %lu already in dn cache\n",
+                   e->e_dn, e->e_id, 0 );
 
                /* free cache mutex */
                pthread_mutex_unlock( &cache->c_mutex );
@@ -122,15 +151,18 @@ cache_add_entry_lock(
        }
 
        /* id tree */
-       if ( avl_insert( &cache->c_idtree, e, cache_entryid_cmp, avl_dup_error )
-           != 0 ) {
-               Debug( LDAP_DEBUG_ANY, "entry %20s id %d already in id cache\n",
+       if ( avl_insert( &cache->c_idtree, (caddr_t) e,
+               cache_entryid_cmp, avl_dup_error ) != 0 )
+       {
+               Debug( LDAP_DEBUG_ANY,
+                       "====> entry %20s id %lu already in id cache\n",
                    e->e_dn, e->e_id, 0 );
 
                /* delete from dn tree inserted above */
-               if ( avl_delete( &cache->c_dntree, e, cache_entrydn_cmp )
-                   == NULL ) {
-                       Debug( LDAP_DEBUG_ANY, "can't delete from dn cache\n",
+               if ( avl_delete( &cache->c_dntree, (caddr_t) e,
+                       cache_entrydn_cmp ) == NULL )
+               {
+                       Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
                            0, 0, 0 );
                }
 
@@ -168,6 +200,11 @@ cache_add_entry_lock(
                     == 0 && cache->c_cursize > cache->c_maxsize ) {
                        e = cache->c_lrutail;
 
+                       /* XXX check for writer lock - should also check no readers pending */
+#ifdef LDAP_DEBUG
+                       assert(!pthread_rdwr_rwchk_np(&e->e_rdwr));
+#endif
+
                        /* delete from cache and lru q */
                        rc = cache_delete_entry_internal( cache, e );
 
@@ -181,44 +218,90 @@ cache_add_entry_lock(
 }
 
 /*
- * cache_find_entry_dn - find an entry in the cache, given dn
+ * cache_find_entry_dn2id - find an entry in the cache, given dn
  */
 
-Entry *
-cache_find_entry_dn(
+ID
+cache_find_entry_dn2id(
+       Backend         *be,
     struct cache       *cache,
     char               *dn
 )
 {
+       struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        Entry           e, *ep;
+       ID                      id;
 
        /* set cache mutex */
        pthread_mutex_lock( &cache->c_mutex );
 
        e.e_dn = dn;
-       if ( (ep = (Entry *) avl_find( cache->c_dntree, &e, cache_entrydn_cmp ))
-           != NULL ) {
+       e.e_ndn = dn_normalize_case( ch_strdup( dn ) );
+
+       if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
+               cache_entrydn_cmp )) != NULL )
+       {
+               free(e.e_ndn);
+
+               Debug(LDAP_DEBUG_TRACE, "====> cache_find_entry_dn2id: found dn: %s\n",
+                       dn, 0, 0);
+
                /*
                 * entry is deleted or not fully created yet
                 */
                if ( ep->e_state == ENTRY_STATE_DELETED ||
-                   ep->e_state == ENTRY_STATE_CREATING )
+                       ep->e_state == ENTRY_STATE_CREATING )
                {
                        /* free cache mutex */
                        pthread_mutex_unlock( &cache->c_mutex );
-                       return( NULL );
+                       return( NOID );
                }
+
+               /* XXX is this safe without writer lock? */
                ep->e_refcnt++;
 
                /* lru */
                LRU_DELETE( cache, ep );
                LRU_ADD( cache, ep );
+
+               /* acquire reader lock */
+               entry_rdwr_lock(ep, 0);
+
+               /* re-check */
+               if ( ep->e_state == ENTRY_STATE_DELETED ||
+                       ep->e_state == ENTRY_STATE_CREATING )
+               {
+                       /* XXX check that is is required */
+                       ep->e_refcnt--;
+
+                       /* free reader lock */
+                       entry_rdwr_unlock(ep, 0);
+                       /* free cache mutex */
+                       pthread_mutex_unlock( &cache->c_mutex );
+
+                       return( NOID );
+               }
+
+               /* save id */
+               id = ep->e_id;
+
+               /* free reader lock */
+               entry_rdwr_unlock(ep, 0);
+
+               /* free cache mutex */
+               pthread_mutex_unlock( &cache->c_mutex );
+
+               cache_return_entry( &li->li_cache, ep );
+
+               return( id );
        }
 
+       free(e.e_ndn);
+
        /* free cache mutex */
        pthread_mutex_unlock( &cache->c_mutex );
 
-       return( ep );
+       return( NOID );
 }
 
 /*
@@ -227,8 +310,9 @@ cache_find_entry_dn(
 
 Entry *
 cache_find_entry_id(
-    struct cache       *cache,
-    ID                 id
+       struct cache    *cache,
+       ID                              id,
+       int                             rw
 )
 {
        Entry   e;
@@ -238,29 +322,64 @@ cache_find_entry_id(
        pthread_mutex_lock( &cache->c_mutex );
 
        e.e_id = id;
-       if ( (ep = (Entry *) avl_find( cache->c_idtree, &e, cache_entryid_cmp ))
-           != NULL ) {
+
+       if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
+               cache_entryid_cmp )) != NULL )
+       {
+               Debug(LDAP_DEBUG_TRACE,
+                       "====> cache_find_entry_dn2id: found id: %ld rw: %d\n",
+                       id, rw, 0);
+
                /*
                 * entry is deleted or not fully created yet
                 */
                if ( ep->e_state == ENTRY_STATE_DELETED ||
-                   ep->e_state == ENTRY_STATE_CREATING )
+                       ep->e_state == ENTRY_STATE_CREATING )
                {
                        /* free cache mutex */
                        pthread_mutex_unlock( &cache->c_mutex );
                        return( NULL );
                }
+               /* XXX is this safe without writer lock? */
                ep->e_refcnt++;
 
                /* lru */
                LRU_DELETE( cache, ep );
                LRU_ADD( cache, ep );
+                
+               /* acquire reader lock */
+               entry_rdwr_lock(ep, 0);
+
+               /* re-check */
+               if ( ep->e_state == ENTRY_STATE_DELETED ||
+                       ep->e_state == ENTRY_STATE_CREATING ) {
+
+                       /* XXX check that is is required */
+                       ep->e_refcnt--;
+
+                       /* free reader lock */
+                       entry_rdwr_unlock(ep, 0);
+
+                       /* free cache mutex */
+                       pthread_mutex_unlock( &cache->c_mutex );
+                       return( NULL );
+               }
+
+               if ( rw ) {
+                       entry_rdwr_unlock(ep, 0);
+                       entry_rdwr_lock(ep, 1);
+               }
+
+               /* free cache mutex */
+               pthread_mutex_unlock( &cache->c_mutex );
+
+               return( ep );
        }
 
        /* free cache mutex */
        pthread_mutex_unlock( &cache->c_mutex );
 
-       return( ep );
+       return( NULL );
 }
 
 /*
@@ -282,6 +401,13 @@ cache_delete_entry(
 {
        int     rc;
 
+       Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry:\n", 0, 0, 0 );
+
+       /* XXX check for writer lock - should also check no readers pending */
+#ifdef LDAP_DEBUG
+       assert(pthread_rdwr_wchk_np(&e->e_rdwr));
+#endif
+
        /* set cache mutex */
        pthread_mutex_lock( &cache->c_mutex );
 
@@ -298,14 +424,24 @@ cache_delete_entry_internal(
     Entry              *e
 )
 {
+       int rc = 0;     /* return code */
+
        /* dn tree */
-       if ( avl_delete( &cache->c_dntree, e, cache_entrydn_cmp ) == NULL ) {
-               return( -1 );
+       if ( avl_delete( &cache->c_dntree, (caddr_t) e, cache_entrydn_cmp )
+               == NULL )
+       {
+               rc = -1;
        }
 
        /* id tree */
-       if ( avl_delete( &cache->c_idtree, e, cache_entryid_cmp ) == NULL ) {
-               return( -1 );
+       if ( avl_delete( &cache->c_idtree, (caddr_t) e, cache_entryid_cmp )
+               == NULL )
+       {
+               rc = -1;
+       }
+
+       if (rc != 0) {
+               return rc;
        }
 
        /* lru */
@@ -329,14 +465,15 @@ lru_print( struct cache *cache )
 
        fprintf( stderr, "LRU queue (head to tail):\n" );
        for ( e = cache->c_lruhead; e != NULL; e = e->e_lrunext ) {
-               fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn,
+               fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
                    e->e_id, e->e_refcnt );
        }
        fprintf( stderr, "LRU queue (tail to head):\n" );
        for ( e = cache->c_lrutail; e != NULL; e = e->e_lruprev ) {
-               fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn,
+               fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
                    e->e_id, e->e_refcnt );
        }
 }
 
 #endif
+