int bdb_dn2id_children( BackendDB *be, DB_TXN *txn, struct berval *dn, int flags ) { int rc; struct bdb_info *bdb = (struct bdb_info *) be->be_private; ID id; idNode *n; rc = bdb_dn2id(be, txn, dn, &id, flags); if (rc != 0) return rc; ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); n = bdb_find_id_node(id, bdb->bi_tree); ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); if (!n->i_kids) return DB_NOTFOUND; else return 0; }
int bdb_dn2idl( BackendDB *be, struct berval *dn, int prefix, ID *ids ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; ID id; idNode *n; if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn)) { BDB_IDL_ALL(bdb, ids); return 0; } rc = bdb_dn2id(be, NULL, dn, &id, 0); if (rc) return rc; ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); n = bdb_find_id_node(id, bdb->bi_tree); ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); ids[0] = 0; ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr); if (prefix == DN_ONE_PREFIX) { rc = avl_apply(n->i_kids, insert_one, ids, -1, AVL_INORDER); } else { ids[0] = 1; ids[1] = id; if (n->i_kids) rc = avl_apply(n->i_kids, insert_sub, ids, -1, AVL_INORDER); } ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr); return rc; }
/* Find the EntryInfo for the requested DN. If the DN cannot be found, return * the info for its closest ancestor. *res should be NULL to process a * complete DN starting from the tree root. Otherwise *res must be the * immediate parent of the requested DN, and only the RDN will be searched. * The EntryInfo is locked upon return and must be unlocked by the caller. */ int bdb_cache_find_ndn( Operation *op, DB_TXN *txn, struct berval *ndn, EntryInfo **res ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; EntryInfo ei, *eip, *ei2; int rc = 0; char *ptr; /* this function is always called with normalized DN */ if ( *res ) { /* we're doing a onelevel search for an RDN */ ei.bei_nrdn.bv_val = ndn->bv_val; ei.bei_nrdn.bv_len = dn_rdnlen( op->o_bd, ndn ); eip = *res; } else { /* we're searching a full DN from the root */ ptr = ndn->bv_val + ndn->bv_len - op->o_bd->be_nsuffix[0].bv_len; ei.bei_nrdn.bv_val = ptr; ei.bei_nrdn.bv_len = op->o_bd->be_nsuffix[0].bv_len; /* Skip to next rdn if suffix is empty */ if ( ei.bei_nrdn.bv_len == 0 ) { for (ptr = ei.bei_nrdn.bv_val - 2; ptr > ndn->bv_val && !DN_SEPARATOR(*ptr); ptr--) /* empty */; if ( ptr >= ndn->bv_val ) { if (DN_SEPARATOR(*ptr)) ptr++; ei.bei_nrdn.bv_len = ei.bei_nrdn.bv_val - ptr; ei.bei_nrdn.bv_val = ptr; } } eip = &bdb->bi_cache.c_dntree; } for ( bdb_cache_entryinfo_lock( eip ); eip; ) { eip->bei_state |= CACHE_ENTRY_REFERENCED; ei.bei_parent = eip; ei2 = (EntryInfo *)avl_find( eip->bei_kids, &ei, bdb_rdn_cmp ); if ( !ei2 ) { DBC *cursor; int len = ei.bei_nrdn.bv_len; if ( BER_BVISEMPTY( ndn )) { *res = eip; return LDAP_SUCCESS; } ei.bei_nrdn.bv_len = ndn->bv_len - (ei.bei_nrdn.bv_val - ndn->bv_val); eip->bei_finders++; bdb_cache_entryinfo_unlock( eip ); BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Reading %s", ei.bei_nrdn.bv_val ); cursor = NULL; rc = bdb_dn2id( op, &ei.bei_nrdn, &ei, txn, &cursor ); if (rc) { bdb_cache_entryinfo_lock( eip ); eip->bei_finders--; if ( cursor ) cursor->c_close( cursor ); *res = eip; return rc; } BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Read got %s(%d)", ei.bei_nrdn.bv_val, ei.bei_id ); /* DN exists but needs to be added to cache */ ei.bei_nrdn.bv_len = len; rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2 ); /* add_internal left eip and c_rwlock locked */ eip->bei_finders--; ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); if ( cursor ) cursor->c_close( cursor ); if ( rc ) { *res = eip; return rc; } } bdb_cache_entryinfo_lock( ei2 ); if ( ei2->bei_state & CACHE_ENTRY_DELETED ) { /* In the midst of deleting? Give it a chance to * complete. */ bdb_cache_entryinfo_unlock( ei2 ); bdb_cache_entryinfo_unlock( eip ); ldap_pvt_thread_yield(); bdb_cache_entryinfo_lock( eip ); *res = eip; return DB_NOTFOUND; } bdb_cache_entryinfo_unlock( eip ); eip = ei2; /* Advance to next lower RDN */ for (ptr = ei.bei_nrdn.bv_val - 2; ptr > ndn->bv_val && !DN_SEPARATOR(*ptr); ptr--) /* empty */; if ( ptr >= ndn->bv_val ) { if (DN_SEPARATOR(*ptr)) ptr++; ei.bei_nrdn.bv_len = ei.bei_nrdn.bv_val - ptr - 1; ei.bei_nrdn.bv_val = ptr; } if ( ptr < ndn->bv_val ) { *res = eip; break; } } return rc; }
int bdb_dn2id_add( BackendDB *be, DB_TXN *txn, struct berval *pdn, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc, rlen, nrlen; DBT key, data; DB *db = bdb->bi_id2parent->bdi_db; diskNode *d; idNode *n; nrlen = dn_rdnlen( be, &e->e_nname ); if (nrlen) { rlen = dn_rdnlen( be, &e->e_name ); } else { rlen = 0; } d = ch_malloc(sizeof(diskNode) + rlen + nrlen + 2); d->rdn.bv_len = rlen; d->nrdn.bv_len = nrlen; d->rdn.bv_val = (char *)(d+1); d->nrdn.bv_val = d->rdn.bv_val + rlen + 1; strncpy(d->rdn.bv_val, e->e_dn, rlen); d->rdn.bv_val[rlen] = '\0'; strncpy(d->nrdn.bv_val, e->e_ndn, nrlen); d->nrdn.bv_val[nrlen] = '\0'; d->rdn.bv_val -= (long)d; d->nrdn.bv_val -= (long)d; if (pdn->bv_len) { bdb_dn2id(be, txn, pdn, &d->parent, 0); } else { d->parent = 0; } DBTzero(&key); DBTzero(&data); key.data = &e->e_id; key.size = sizeof(ID); key.flags = DB_DBT_USERMEM; data.data = d; data.size = sizeof(diskNode) + rlen + nrlen + 2; data.flags = DB_DBT_USERMEM; rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); if (rc == 0) { ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr); n = bdb_add_node( e->e_id, data.data, bdb); ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr); if (d->parent) { ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); bdb_insert_kid(n, bdb->bi_tree); ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); } } else { free(d); } return rc; }