From: Howard Chu Date: Sun, 14 Sep 2003 10:27:59 +0000 (+0000) Subject: More deadlock tweaks. X-Git-Tag: OPENLDAP_REL_ENG_2_1_MP~725 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=aee837c9990f65caa51f0507a47c2fc0ed9a11de;p=openldap More deadlock tweaks. --- diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index c9f17b6493..69b7f1ccb8 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -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; }