From: Howard Chu Date: Tue, 22 Apr 2003 17:06:35 +0000 (+0000) Subject: Trim dead BDB_HIER stuff X-Git-Tag: OPENLDAP_REL_ENG_2_2_0ALPHA~290 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=68822b1e15efd4ac0d6a253d42d13218f68ee698;p=openldap Trim dead BDB_HIER stuff --- diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index 9801243cb0..c6743eb315 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -14,8 +14,6 @@ LDAP_BEGIN_DECL -/* #define BDB_HIER 1 */ - #define DN_BASE_PREFIX SLAP_INDEX_EQUALITY_PREFIX #define DN_ONE_PREFIX '%' #define DN_SUBTREE_PREFIX '@' @@ -40,11 +38,7 @@ LDAP_BEGIN_DECL #define BDB_SUFFIX ".bdb" #define BDB_ID2ENTRY 0 -#ifdef BDB_HIER -#define BDB_ID2PARENT 1 -#else #define BDB_DN2ID 1 -#endif #define BDB_NDB 2 /* The bdb on-disk entry format is pretty space-inefficient. Average @@ -90,6 +84,7 @@ typedef struct bdb_entry_info { int bei_state; #define CACHE_ENTRY_DELETED 1 #define CACHE_ENTRY_NO_KIDS 2 +#define CACHE_ENTRY_NOT_LINKED 4 /* * remaining fields require backend cache lock to access @@ -146,11 +141,6 @@ struct bdb_info { Avlnode *bi_attrs; void *bi_search_stack; int bi_search_stack_depth; -#ifdef BDB_HIER - Avlnode *bi_tree; - ldap_pvt_thread_rdwr_t bi_tree_rdwr; - void *bi_troot; -#endif int bi_txn_cp; u_int32_t bi_txn_cp_min; @@ -159,6 +149,8 @@ struct bdb_info { int bi_lock_detect; long bi_shm_key; + int bi_is_hier; + ID bi_lastid; ldap_pvt_thread_mutex_t bi_lastid_mutex; #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index ab1ad2940f..3437ef3c75 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -50,6 +50,8 @@ bdb_cache_entry_db_relock( DBT lockobj; DB_LOCKREQ list[2]; + if ( !lock ) return 0; + lockobj.data = ei; lockobj.size = sizeof(ei->bei_parent) + sizeof(ei->bei_id); @@ -89,6 +91,8 @@ bdb_cache_entry_db_lock DBT lockobj; int db_rw; + if ( !lock ) return 0; + if (rw) db_rw = DB_LOCK_WRITE; else @@ -184,9 +188,7 @@ bdb_id_cmp( const void *v_e1, const void *v_e2 ) int bdb_entryinfo_add_internal( struct bdb_info *bdb, - EntryInfo *eip, - ID id, - struct berval *nrdn, + EntryInfo *ei, EntryInfo **res, u_int32_t locker ) @@ -202,15 +204,15 @@ bdb_entryinfo_add_internal( *res = NULL; ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock ); - bdb_cache_entryinfo_lock( eip ); + bdb_cache_entryinfo_lock( ei->bei_parent ); /* if parent was previously considered a leaf node, * it was on the LRU list. Now it's going to have * kids, take it off the LRU list. */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); - if ( eip->bei_id && !eip->bei_kids ) { - LRU_DELETE( cache, eip ); + if ( ei->bei_parent->bei_id && !ei->bei_parent->bei_kids ) { + LRU_DELETE( cache, ei->bei_parent ); incr = 0; } @@ -265,33 +267,32 @@ bdb_entryinfo_add_internal( if (!ei2) { ei2 = bdb_cache_entryinfo_new(); } - ei2->bei_id = id; - ei2->bei_parent = eip; + ei2->bei_id = ei->bei_id; + ei2->bei_parent = ei->bei_parent; + ei2->bei_rdn = ei->bei_rdn; /* Add to cache ID tree */ if (avl_insert( &cache->c_idtree, ei2, bdb_id_cmp, avl_dup_error )) { - EntryInfo *ei; - ei = avl_find( cache->c_idtree, ei2, bdb_id_cmp ); + EntryInfo *eix; + eix = avl_find( cache->c_idtree, ei2, bdb_id_cmp ); bdb_cache_entryinfo_destroy( ei2 ); - ei2 = ei; + ei2 = eix; addkid = 0; cache->c_cursize -= incr; + if ( ei->bei_rdn.bv_val ) + ber_memfree_x( ei->bei_rdn.bv_val, NULL ); } else { LRU_ADD( cache, ei2 ); - ber_dupbv( &ei2->bei_nrdn, nrdn ); + ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn ); } if ( addkid ) { - avl_insert( &eip->bei_kids, ei2, bdb_rdn_cmp, avl_dup_error ); + avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp, + avl_dup_error ); } ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); -#if 0 /* caller must do these frees */ - ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); - bdb_cache_entryinfo_unlock( eip ); -#endif - *res = ei2; return 0; } @@ -332,6 +333,7 @@ bdb_cache_find_entry_ndn2id( } for ( bdb_cache_entryinfo_lock( eip ); eip; ) { + ei.bei_parent = eip; ei2 = (EntryInfo *)avl_find( eip->bei_kids, &ei, bdb_rdn_cmp ); if ( !ei2 ) { int len = ei.bei_nrdn.bv_len; @@ -348,8 +350,8 @@ bdb_cache_find_entry_ndn2id( /* DN exists but needs to be added to cache */ ei.bei_nrdn.bv_len = len; - rc = bdb_entryinfo_add_internal( bdb, - eip, ei.bei_id, &ei.bei_nrdn, &ei2, locker ); + rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2, + locker ); /* add_internal left eip and c_rwlock locked */ ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); if ( rc ) { @@ -388,6 +390,99 @@ bdb_cache_find_entry_ndn2id( return rc; } +#ifdef BDB_HIER +/* Walk up the tree from a child node, looking for an ID that's already + * been linked into the cache. + */ +int +bdb_cache_find_parent( + Backend *be, + DB_TXN *txn, + ID id, + EntryInfo **res, + void *ctx +) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + EntryInfo ei, eip, *ei2 = NULL, *ein = NULL, *eir = NULL; + ID parent; + int rc; + + ei.bei_id = id; + ei.bei_kids = NULL; + + for (;;) { + rc = bdb_dn2id_parent( be, txn, &ei, &eip.bei_id, ctx ); + if ( rc ) break; + + /* Save the previous node, if any */ + ei2 = ein; + + /* Create a new node for the current ID */ + ein = bdb_cache_entryinfo_new(); + ein->bei_id = ei.bei_id; + ein->bei_nrdn = ei.bei_nrdn; + ein->bei_rdn = ei.bei_rdn; + ein->bei_kids = ei.bei_kids; + + /* This node is not fully connected yet */ + ein->bei_state = CACHE_ENTRY_NOT_LINKED; + + /* If this is the first time, save this node + * to be returned later. + */ + if ( eir == NULL ) eir = ein; + + /* Insert this node into the ID tree */ + ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock ); + if ( avl_insert( &bdb->bi_cache.c_idtree, (caddr_t)ein, + bdb_id_cmp, avl_dup_error ) ) { + + /* Hm, can this really happen? */ + bdb_cache_entryinfo_destroy( ein ); + ein = (EntryInfo *)avl_find( bdb->bi_cache.c_idtree, + (caddr_t) &ei, bdb_id_cmp ); + 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 there was a previous node, link it to this one */ + if ( ei2 ) ei2->bei_parent = ein; + + 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; + } + + if ( ei2 ) { + ein->bei_parent = ei2; + bdb_cache_entryinfo_lock( 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_runlock( &bdb->bi_cache.c_rwlock ); + if ( ei2 ) { + /* Found a link. Reset all the state info */ + for (ein = eir; ein != ei2; ein=ein->bei_parent) + ein->bei_state &= ~CACHE_ENTRY_NOT_LINKED; + break; + } + ei.bei_kids = NULL; + ei.bei_id = eip.bei_id; + avl_insert( &ei.bei_kids, (caddr_t)ein, bdb_rdn_cmp, + avl_dup_error ); + } + return rc; +} +#endif + /* * cache_find_entry_id - find an entry in the cache, given id. * The entry is locked for Read upon return. Call with islocked TRUE if @@ -427,6 +522,7 @@ bdb_cache_find_entry_id( /* See if the ID exists in the database; add it to the cache if so */ if ( !*eip ) { +#ifndef BDB_HIER rc = bdb_id2entry( be, tid, id, &ep ); if ( rc == 0 ) { rc = bdb_cache_find_entry_ndn2id( be, tid, @@ -438,6 +534,11 @@ bdb_cache_find_entry_id( ep = NULL; } } +#else + rc = bdb_cache_find_parent(be, tid, id, eip, ctx ); + if ( rc == 0 && *eip ) + islocked = 1; +#endif } /* Ok, we found the info, do we have the entry? */ @@ -451,8 +552,11 @@ bdb_cache_find_entry_id( if ( rc == 0 ) { bdb_cache_entry_db_lock( bdb->bi_dbenv, locker, *eip, 1, 0, lock ); - (*eip)->bei_e = ep; ep->e_private = *eip; +#ifdef BDB_HIER + hdb_fix_dn( ep ); +#endif + (*eip)->bei_e = ep; bdb_cache_entry_db_relock( bdb->bi_dbenv, locker, *eip, 0, 0, lock ); } @@ -501,21 +605,30 @@ bdb_cache_children( int bdb_cache_add( struct bdb_info *bdb, - EntryInfo *ei, + EntryInfo *eip, Entry *e, struct berval *nrdn, u_int32_t locker ) { - EntryInfo *new; + EntryInfo *new, ei; + struct berval rdn = e->e_name; int rc; - rc = bdb_entryinfo_add_internal( bdb, ei, e->e_id, nrdn, &new, locker ); + ei.bei_id = e->e_id; + ei.bei_parent = eip; + ei.bei_nrdn = *nrdn; + if ( nrdn->bv_len != e->e_nname.bv_len ) { + char *ptr = strchr( rdn.bv_val, ',' ); + rdn.bv_len = ptr - rdn.bv_val; + } + ber_dupbv( &ei.bei_rdn, &rdn ); + rc = bdb_entryinfo_add_internal( bdb, &ei, &new, locker ); new->bei_e = e; e->e_private = new; new->bei_state = CACHE_ENTRY_NO_KIDS; - ei->bei_state &= ~CACHE_ENTRY_NO_KIDS; - bdb_cache_entryinfo_unlock( ei ); + eip->bei_state &= ~CACHE_ENTRY_NO_KIDS; + bdb_cache_entryinfo_unlock( eip ); ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); return rc; } @@ -560,6 +673,7 @@ bdb_cache_modrdn( ) { EntryInfo *ei = BEI(e), *pei; + struct berval rdn; int rc = 0; /* Get write lock on data */ @@ -589,7 +703,15 @@ bdb_cache_modrdn( bdb_cache_entryinfo_lock( pei ); avl_delete( &pei->bei_kids, (caddr_t) ei, bdb_rdn_cmp ); free( ei->bei_nrdn.bv_val ); + free( ei->bei_rdn.bv_val ); ber_dupbv( &ei->bei_nrdn, nrdn ); + rdn = e->e_name; + if ( nrdn->bv_len != e->e_nname.bv_len ) { + char *ptr = strchr(rdn.bv_val, ','); + rdn.bv_len = ptr - rdn.bv_val; + } + ber_dupbv( &ei->bei_rdn, &rdn ); + if (!ein) { ein = ei->bei_parent; } else { @@ -702,7 +824,9 @@ static void bdb_entryinfo_release( void *data ) { EntryInfo *ei = (EntryInfo *)data; - avl_free( ei->bei_kids, NULL ); + if ( ei->bei_kids ) { + avl_free( ei->bei_kids, NULL ); + } if ( ei->bei_e ) { ei->bei_e->e_private = NULL; bdb_entry_return( ei->bei_e ); diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 32511ce863..abb1161bce 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -487,9 +487,10 @@ bdb_dn2idl( * entry in this database is a struct diskNode, keyed by entryID and with * the data containing the RDN and entryID of the node's children. We use * a B-Tree with sorted duplicates to store all the children of a node under - * the same key. Also, the first item under the key contains an empty rdn - * and the ID of the node's parent, to allow bottom-up tree traversal as - * well as top-down. + * the same key. Also, the first item under the key contains the entry's own + * rdn and the ID of the node's parent, to allow bottom-up tree traversal as + * well as top-down. To keep this info first in the list, the nrdnlen is set + * to the negative of its value. * * The diskNode is a variable length structure. This definition is not * directly usable for in-memory manipulation. @@ -505,7 +506,7 @@ typedef struct diskNode { * Sorts based on normalized RDN, in lexical order. */ int -bdb_hdb_compare( +hdb_dup_compare( DB *db, const DBT *usrkey, const DBT *curkey @@ -513,30 +514,45 @@ bdb_hdb_compare( { diskNode *usr = usrkey->data; diskNode *cur = curkey->data; - short curlen; - char *ptr = (char *)&cur->nrdnlen; + short curlen, usrlen; + char *ptr; + unsigned char *pt2; int rc; - curlen = ptr[0] << 8 | ptr[1]; + /* Make sure to detect negative values in the nrdnlen */ + ptr = (char *)&usr->nrdnlen; + pt2 = (unsigned char *)(ptr+1); + + usrlen = ptr[0] << 8 | *pt2; + + ptr = (char *)&cur->nrdnlen; + pt2 = (unsigned char *)(ptr+1); + + curlen = ptr[0] << 8 | *pt2; + + if ( usrlen < 0 ) { + if ( curlen < 0 ) return 0; + return -1; + } + + if ( curlen < 0 ) return 1; - rc = strncmp( usr->nrdn, cur->nrdn, usr->nrdnlen ); + rc = strncmp( usr->nrdn, cur->nrdn, usrlen ); if ( rc == 0 ) rc = usrlen - curlen; return rc; } /* This function constructs a full DN for a given entry. */ -int bdb_fix_dn( - BackendDB *be, +int hdb_fix_dn( Entry *e ) { - struct bdb_info *bdb = (struct bdb_info *) be->be_private; EntryInfo *ei; int rlen = 0, nrlen = 0; char *ptr, *nptr; - for ( ei = BEI(e); ei; ei=ei->bei_parent ) { + for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) { rlen += ei->bei_rdn.bv_len + 1; nrlen += ei->bei_nrdn.bv_len + 1; } @@ -546,7 +562,7 @@ int bdb_fix_dn( e->e_nname.bv_val = e->e_name.bv_val + rlen; ptr = e->e_name.bv_val; nptr = e->e_nname.bv_val; - for ( ei = BEI(e); ei; ei=ei->bei_parent ) { + for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) { ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val); nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val); if ( ei->bei_parent ) { @@ -554,8 +570,8 @@ int bdb_fix_dn( *nptr++ = ','; } } - *ptr = '\0'; - *nptr = '\0'; + ptr[-1] = '\0'; + nptr[-1] = '\0'; return 0; } @@ -607,20 +623,17 @@ bdb_dn2id_add( } #endif data.data = d; - data.size = sizeof(diskNode) + rlen + nrlen + 2; + data.size = sizeof(diskNode) + rlen + nrlen; data.flags = DB_DBT_USERMEM; - rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); + rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); if (rc == 0) { key.data = &e->e_id; d->entryID = eip->bei_id; - d->nrdnlen = 0; - d->nrdn[0] = '\0'; - d->rdn[0] = '\0'; - data.size = sizeof(diskNode); + d->nrdnlen = 0 - nrlen; - rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); + rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); } sl_free( d, ctx ); @@ -650,12 +663,7 @@ bdb_dn2id_delete( key.flags = DB_DBT_USERMEM; DBTzero(&data); - data.size = sizeof(diskNode) + BEI(e)->nrdn.bv_len; - d = sl_malloc( data.size, ctx ); - d->entryID = e->e_id; - d->nrdnlen = BEI(e)->nrdn.bv_len; - strcpy( d->nrdn, BEI(e)->nrdn.bv_val ); - data.data = d; + data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len; data.ulen = data.size; data.dlen = data.size; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; @@ -668,13 +676,28 @@ bdb_dn2id_delete( rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; + d = sl_malloc( data.size, ctx ); + d->entryID = e->e_id; + d->nrdnlen = BEI(e)->bei_nrdn.bv_len; + strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val ); + data.data = d; + + /* Delete our ID from the parent's list */ rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW ); if ( rc == 0 ) rc = cursor->c_del( cursor, 0 ); - cursor->c_close( cursor ); - key.data = &e->e_id; - rc = db->del( db, txn, &key, 0); + /* Delete our ID from the tree. With sorted duplicates, this + * will leave any child nodes still hanging around. This is OK + * for modrdn, which will add our info back in later. + */ + if ( rc == 0 ) { + key.data = &e->e_id; + rc = cursor->c_get( cursor, &key, &data, DB_SET ); + if ( rc == 0 ) + rc = cursor->c_del( cursor, 0 ); + } + cursor->c_close( cursor ); sl_free( d, ctx ); return rc; @@ -693,38 +716,96 @@ bdb_dn2id( DBT key, data; DBC *cursor; int rc = 0, nrlen; + diskNode *d; char *ptr; + ID idp = ei->bei_parent->bei_id; - nrlen = dn_rdnlen( be, &in ); + nrlen = dn_rdnlen( be, in ); if (!nrlen) nrlen = in->bv_len; DBTzero(&key); key.size = sizeof(ID); - key.data = &eip->bei_id; + key.data = &idp; + key.ulen = sizeof(ID); key.flags = DB_DBT_USERMEM; DBTzero(&data); data.size = sizeof(diskNode) + nrlen; - d = sl_malloc( data.size * 3, ctx ); - d->nrdnlen = nrlen; - ptr = lutil_strncopy( d->nrdn, BEI(e)->nrdn.bv_val, nrlen ); - *ptr = '\0'; - data.data = d; data.ulen = data.size * 3; data.flags = DB_DBT_USERMEM; rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; + d = sl_malloc( data.size * 3, ctx ); + d->nrdnlen = nrlen; + ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen ); + *ptr = '\0'; + data.data = d; + rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH ); cursor->c_close( cursor ); + + if ( rc == 0 ) { + AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) ); + ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen; + ptr = d->nrdn + nrlen + 1; + ei->bei_rdn.bv_val = ch_malloc( ei->bei_rdn.bv_len + 1 ); + strcpy( ei->bei_rdn.bv_val, ptr ); + } + sl_free( d, ctx ); + + return rc; +} + +int +bdb_dn2id_parent( + Backend *be, + DB_TXN *txn, + EntryInfo *ei, + ID *idp, + void *ctx ) +{ + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + DB *db = bdb->bi_dn2id->bdi_db; + DBT key, data; + DBC *cursor; + int rc = 0; + diskNode *d; + char *ptr; + unsigned char *pt2; + + DBTzero(&key); + key.size = sizeof(ID); + key.data = &ei->bei_id; + key.ulen = sizeof(ID); + key.flags = DB_DBT_USERMEM; + + DBTzero(&data); + data.flags = DB_DBT_USERMEM; + + rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; - AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) ); - ei->rdn.bv_len = data.size - sizeof(diskNode) - nrlen; - ptr = d->nrdn + nrlen + 1; - strcpy( ei->rdn.bv_val, ptr ); + data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2); + d = sl_malloc( data.ulen, ctx ); + data.data = d; + rc = cursor->c_get( cursor, &key, &data, DB_SET ); + cursor->c_close( cursor ); + if ( rc == 0 ) { + if (d->nrdnlen >= 0) { + return LDAP_OTHER; + } + AC_MEMCPY( idp, &d->entryID, sizeof(ID) ); + ei->bei_nrdn.bv_len = 0 - d->nrdnlen; + ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn ); + ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - + ei->bei_nrdn.bv_len; + ptr = d->nrdn + ei->bei_nrdn.bv_len + 1; + ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn ); + } + sl_free( d, ctx ); return rc; } @@ -751,12 +832,12 @@ bdb_dn2id_children( if ( bdb->bi_idl_cache_size ) { rc = bdb_idl_cache_get( bdb, db, &key, NULL ); if ( rc != LDAP_NO_SUCH_OBJECT ) { - sl_free( key.data, o->o_tmpmemctx ); return rc; } } #endif DBTzero(&data); + data.data = &d; data.ulen = sizeof(d); data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; data.dlen = sizeof(d); @@ -764,7 +845,7 @@ bdb_dn2id_children( rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; - rc = cursor->c_get( cursor, &key, &data, DB_FIRST ); + rc = cursor->c_get( cursor, &key, &data, DB_SET ); if ( rc == 0 ) { rc = cursor->c_get( cursor, &key, &data, DB_NEXT_DUP ); } @@ -772,6 +853,16 @@ bdb_dn2id_children( return rc; } +/* bdb_dn2idl: + * We can't just use bdb_idl_fetch_key because + * 1 - our data items are longer than just an entry ID + * 2 - our data items are sorted alphabetically by nrdn, not by ID. + * + * We descend the tree recursively, so we define this cookie + * to hold our necessary state information. The bdb_dn2idl_internal + * function uses this cookie when calling itself. + */ + struct dn2id_cookie { struct bdb_info *bdb; DB *db; @@ -781,25 +872,17 @@ struct dn2id_cookie { ID dbuf; ID *ids; ID tmp[BDB_IDL_DB_SIZE]; - ID buf[BDB_IDL_UM_SIZE]; DBT key; DBT data; - DBC dbc; - void *ptr; + DBC *dbc; void *ctx; }; -/* We can't just use bdb_idl_fetch_key because - * 1 - our data items are longer than just an entry ID - * 2 - our data items are sorted alphabetically by nrdn, not by ID. - */ int bdb_dn2idl_internal( struct dn2id_cookie *cx ) { - ID *save, *i; - #ifdef SLAP_IDL_CACHE if ( cx->bdb->bi_idl_cache_size ) { cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp); @@ -807,39 +890,60 @@ bdb_dn2idl_internal( return cx->rc; } if ( cx->rc == LDAP_SUCCESS ) { - readit = 0; + goto saveit; } } #endif - - cx->data.data = &cx->dbuf; - cx->data.ulen = sizeof(ID); - cx->data.dlen = sizeof(ID); - cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; - cx->rc = db->cursor( cx->db, NULL, &cx->dbc, cx->bdb->bi_db_opflags ); + cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc, + cx->bdb->bi_db_opflags ); if ( cx->rc ) return cx->rc; BDB_IDL_ZERO( cx->tmp ); - cx->rc = dbc->c_get( dbc, &cx->key, &cx->data, DB_FIRST ); - cx->data.data = &cx->buf; - cx->data.ulen = sizeof(cx->buf); - while ( cx->rc == 0 ) { - u_int8_t *j; - size_t len; - cx->rc = dbc->c_get( dbc, &cx->key, &cx->data, DB_MULTIPLE | - DB_NEXT_DUP ); - DB_MULTIPLE_INIT( cx->ptr, &cx->data ); - while (cx->ptr) { - DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len ); - if (j) { - AC_MEMCPY( &cx->dbuf, j, sizeof(ID) ); - bdb_idl_insert( cx->tmp, cx->dbuf ); + /* The first item holds the parent ID. Ignore it. */ + cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET ); + if ( cx->rc == DB_NOTFOUND ) goto saveit; + if ( cx->rc ) return cx->rc; + + /* Fetch the rest of the IDs in a loop... */ + while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, + DB_NEXT_DUP )) == 0 ) { + bdb_idl_insert( cx->tmp, cx->dbuf ); + } + cx->dbc->c_close( cx->dbc ); + + /* If we got some records, treat as success */ + if (!BDB_IDL_IS_ZERO(cx->tmp)) { + cx->rc = 0; + } + +saveit: +#ifdef SLAP_IDL_CACHE + if ( cx->bdb->bi_idl_cache_max_size ) { + bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc ); + } +#endif + if ( cx->rc == 0 ) { + if ( cx->prefix == DN_SUBTREE_PREFIX ) { + ID *save, idcurs; + + save = sl_malloc( BDB_IDL_SIZEOF( cx->tmp ), cx->ctx ); + BDB_IDL_CPY( save, cx->tmp ); + bdb_idl_union( cx->ids, cx->tmp ); + + idcurs = 0; + for ( cx->id = bdb_idl_first( save, &idcurs ); + cx->id != NOID; + cx->id = bdb_idl_next( save, &idcurs )) { + bdb_dn2idl_internal( cx ); } + sl_free( save, cx->ctx ); + cx->rc = 0; + } else { + BDB_IDL_CPY( cx->ids, cx->tmp ); } } - dbc->c_close( dbc ); - + return cx->rc; } int @@ -860,11 +964,22 @@ bdb_dn2idl( cx.ids = ids; cx.ctx = ctx; + BDB_IDL_ZERO( ids ); + if ( prefix == DN_SUBTREE_PREFIX ) { + bdb_idl_insert( ids, cx.id ); + } + DBTzero(&cx.key); cx.key.data = &cx.id; + cx.key.ulen = sizeof(ID); cx.key.size = sizeof(ID); cx.key.flags = DB_DBT_USERMEM; + DBTzero(&cx.data); + cx.data.data = &cx.dbuf; + cx.data.ulen = sizeof(ID); + cx.data.dlen = sizeof(ID); + cx.data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; return bdb_dn2idl_internal(&cx); } diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index 72f88232b9..af84680994 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -96,6 +96,7 @@ bdb_db_init( BackendDB *be ) ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex ); ldap_pvt_thread_mutex_init( &bdb->bi_cache.lru_mutex ); + ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_dntree.bei_kids_mutex ); ldap_pvt_thread_rdwr_init ( &bdb->bi_cache.c_rwlock ); be->be_private = bdb; @@ -363,14 +364,16 @@ bdb_db_open( BackendDB *be ) rc = db->bdi_db->set_pagesize( db->bdi_db, BDB_ID2ENTRY_PAGESIZE ); } else { -#ifdef BDB_HIER - rc = db->bdi_db->set_bt_compare( db->bdi_db, - bdb_bt_compare ); -#else rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT ); +#ifndef BDB_HIER rc = db->bdi_db->set_dup_compare( db->bdi_db, bdb_bt_compare ); +#else + rc = db->bdi_db->set_dup_compare( db->bdi_db, + hdb_dup_compare ); + rc = db->bdi_db->set_bt_compare( db->bdi_db, + bdb_bt_compare ); #endif rc = db->bdi_db->set_pagesize( db->bdi_db, BDB_PAGESIZE ); @@ -519,6 +522,7 @@ bdb_db_destroy( BackendDB *be ) ldap_pvt_thread_rdwr_destroy ( &bdb->bi_cache.c_rwlock ); ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.lru_mutex ); + ldap_pvt_thread_mutex_destroy( &bdb->bi_cache.c_dntree.bei_kids_mutex ); ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex ); #ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 91c8a883f4..f8e1256d26 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -93,6 +93,15 @@ bdb_dn2idl( ID *ids, void *ctx ); +#ifdef BDB_HIER +int hdb_dup_compare( + DB *db, + const DBT *usrkey, + const DBT *curkey ); + +int hdb_fix_dn( Entry *e ); +#endif + /* * entry.c */ diff --git a/servers/slapd/back-bdb/tools.c b/servers/slapd/back-bdb/tools.c index 631cf65f92..5a304a4f5e 100644 --- a/servers/slapd/back-bdb/tools.c +++ b/servers/slapd/back-bdb/tools.c @@ -113,6 +113,7 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id ) assert( slapMode & SLAP_TOOL_MODE ); assert( data.data != NULL ); +#ifndef BDB_HIER DBT2bv( &data, &bv ); rc = entry_decode( &bv, &e ); @@ -120,11 +121,15 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id ) if( rc == LDAP_SUCCESS ) { e->e_id = id; } - -#ifdef BDB_HIER - bdb_fix_dn(be, id, e); +#else + { + EntryInfo *ei = NULL; + rc = bdb_cache_find_entry_id( be, NULL, id, &ei, 0, 0, + NULL, NULL ); + if ( rc == LDAP_SUCCESS ) + e = ei->bei_e; + } #endif - return e; }