mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-14 19:04:21 -05:00
Trim dead BDB_HIER stuff
This commit is contained in:
parent
c9f8d7accb
commit
68822b1e15
6 changed files with 371 additions and 122 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
rc = strncmp( usr->nrdn, cur->nrdn, usr->nrdnlen );
|
||||
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, 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue