]> git.sur5r.net Git - openldap/commitdiff
More deadlock tweaks.
authorHoward Chu <hyc@openldap.org>
Sun, 14 Sep 2003 10:27:59 +0000 (10:27 +0000)
committerHoward Chu <hyc@openldap.org>
Sun, 14 Sep 2003 10:27:59 +0000 (10:27 +0000)
servers/slapd/back-bdb/cache.c

index c9f17b6493a39aba089bc7b27aa3478050d9ca24..69b7f1ccb8695b39a9735d861f3d6aaf85110f69 100644 (file)
@@ -239,7 +239,11 @@ bdb_entryinfo_add_internal(
                         */
                        if ( bdb_cache_entry_db_lock( env, locker, elru, 1, 1,
                                &lock ) == 0 ) {
-                               if ( !elru->bei_e ) {
+                               /* If there's no entry, or this node is in
+                                * the process of linking into the cache,
+                                * skip it.
+                                */
+                               if ( !elru->bei_e || (elru->bei_state & CACHE_ENTRY_NOT_LINKED) ) {
                                        bdb_cache_entry_db_unlock( env, &lock );
                                        continue;
                                }
@@ -422,8 +426,10 @@ hdb_cache_find_parent(
 {
        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
        EntryInfo ei, eip, *ei2 = NULL, *ein = NULL, *eir = NULL;
+       char ndn[SLAP_LDAPDN_MAXLEN];
        ID parent;
        int rc;
+       int addlru = 1;
 
        ei.bei_id = id;
        ei.bei_kids = NULL;
@@ -450,16 +456,24 @@ hdb_cache_find_parent(
                if ( avl_insert( &bdb->bi_cache.c_idtree, (caddr_t)ein,
                        bdb_id_cmp, avl_dup_error ) ) {
 
-                       /* Hm, can this really happen? */
+                       /* Someone else created this node just before us.
+                        * Free our new copy and use the existing one.
+                        */
                        bdb_cache_entryinfo_destroy( ein );
                        ein = (EntryInfo *)avl_find( bdb->bi_cache.c_idtree,
                                (caddr_t) &ei, bdb_id_cmp );
+                       
+                       /* Link in any kids we've already processed */
                        if ( ei2 ) {
                                bdb_cache_entryinfo_lock( ein );
                                avl_insert( &ein->bei_kids, (caddr_t)ei2,
                                        bdb_rdn_cmp, avl_dup_error );
                                bdb_cache_entryinfo_unlock( ein );
                        }
+
+                       if ( !eir ) {
+                               addlru = 0;
+                       }
                }
 
                /* If this is the first time, save this node
@@ -470,27 +484,28 @@ hdb_cache_find_parent(
                /* If there was a previous node, link it to this one */
                if ( ei2 ) ei2->bei_parent = ein;
 
+               /* Look for this node's parent */
                if ( eip.bei_id ) {
                        ei2 = (EntryInfo *) avl_find( bdb->bi_cache.c_idtree,
                                        (caddr_t) &eip, bdb_id_cmp );
                } else {
                        ei2 = &bdb->bi_cache.c_dntree;
                }
+               ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
 
+               /* Got the parent, link in and we're done. */
                if ( ei2 ) {
-                       ein->bei_parent = ei2;
                        bdb_cache_entryinfo_lock( ei2 );
+                       ein->bei_parent = ei2;
                        avl_insert( &ei2->bei_kids, (caddr_t)ein, bdb_rdn_cmp,
                                avl_dup_error);
                        bdb_cache_entryinfo_unlock( ei2 );
-                       *res = eir;
                        bdb_cache_entryinfo_lock( eir );
-               }
-               ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
-               if ( ei2 ) {
-                       /* Found a link. Reset all the state info */
+
+                       /* Reset all the state info */
                        for (ein = eir; ein != ei2; ein=ein->bei_parent)
                                ein->bei_state &= ~CACHE_ENTRY_NOT_LINKED;
+                       *res = eir;
                        break;
                }
                ei.bei_kids = NULL;
@@ -532,12 +547,26 @@ again:            ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock );
                *eip = (EntryInfo *) avl_find( bdb->bi_cache.c_idtree,
                                        (caddr_t) &ei, bdb_id_cmp );
                if ( *eip ) {
+                       /* If the lock attempt fails, the info is in use */
                        if ( ldap_pvt_thread_mutex_trylock(
                                        &(*eip)->bei_kids_mutex )) {
                                ldap_pvt_thread_rdwr_runlock( &bdb->bi_cache.c_rwlock );
+                               /* If this node is being deleted, treat
+                                * as if the delete has already finished
+                                */
                                if ( (*eip)->bei_state & CACHE_ENTRY_DELETED ) {
                                        return DB_NOTFOUND;
                                }
+                               /* otherwise, wait for the info to free up */
+                               ldap_pvt_thread_yield();
+                               goto again;
+                       }
+                       /* If this info isn't hooked up to its parent yet,
+                        * unlock and wait for it to be fully initialized
+                        */
+                       if ( (*eip)->bei_state & CACHE_ENTRY_NOT_LINKED ) {
+                               bdb_cache_entryinfo_unlock( *eip );
+                               ldap_pvt_thread_rdwr_runlock( &bdb->bi_cache.c_rwlock );
                                ldap_pvt_thread_yield();
                                goto again;
                        }