]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-bdb/dn2id.c
ITS#4040 move initialization
[openldap] / servers / slapd / back-bdb / dn2id.c
index b157ad23a9245f40b15eff0d8005893ef342181b..5131fd1a9fe20df68e6d9375533b4cce5f00d5ce 100644 (file)
@@ -361,6 +361,7 @@ bdb_dn2idl(
        ((char *)key.data)[0] = prefix;
        AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
 
+       BDB_IDL_ZERO( ids );
        rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids, NULL, 0 );
 
        if( rc != 0 ) {
@@ -380,10 +381,7 @@ bdb_dn2idl(
 }
 
 #else  /* BDB_HIER */
-/* Experimental management routines for a hierarchically structured database.
- *
- * Unsupported! Use at your own risk!
- * -- Howard Chu, Symas Corp. 2003.
+/* Management routines for a hierarchically structured database.
  *
  * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
  * entry in this database is a struct diskNode, keyed by entryID and with
@@ -401,9 +399,9 @@ bdb_dn2idl(
  */
 typedef struct diskNode {
        unsigned char nrdnlen[2];
-       unsigned char nrdn[1];
-       unsigned char rdn[1];
-       unsigned char entryID[sizeof(ID)];
+       char nrdn[1];
+       char rdn[1];                        /* variable placement */
+       unsigned char entryID[sizeof(ID)];  /* variable placement */
 } diskNode;
 
 /* This function constructs a full DN for a given entry.
@@ -417,6 +415,9 @@ int hdb_fix_dn(
        char *ptr, *nptr;
        int max = 0;
 
+       if ( !e->e_id )
+               return 0;
+
        /* count length of all DN components */
        for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
                rlen += ei->bei_rdn.bv_len + 1;
@@ -497,16 +498,22 @@ hdb_dn2id_add(
 
        DBTzero(&key);
        DBTzero(&data);
-       key.data = &nid;
        key.size = sizeof(ID);
        key.flags = DB_DBT_USERMEM;
        BDB_ID2DISK( eip->bei_id, &nid );
 
+       /* Delete parent's IDL cache entry */
+       if ( bdb->bi_idl_cache_size ) {
+               key.data = &eip->bei_id;
+               bdb_idl_cache_del( bdb, db, &key );
+       }
+       key.data = &nid;
+
        /* Need to make dummy root node once. Subsequent attempts
         * will fail harmlessly.
         */
        if ( eip->bei_id == 0 ) {
-               diskNode dummy = {0};
+               diskNode dummy = {{0, 0}, "", "", ""};
                data.data = &dummy;
                data.size = sizeof(diskNode);
                data.flags = DB_DBT_USERMEM;
@@ -514,9 +521,6 @@ hdb_dn2id_add(
                db->put( db, txn, &key, &data, DB_NODUPDATA );
        }
 
-       if ( bdb->bi_idl_cache_size ) {
-               bdb_idl_cache_del( bdb, db, &key );
-       }
        data.data = d;
        data.size = sizeof(diskNode) + rlen + nrlen;
        data.flags = DB_DBT_USERMEM;
@@ -548,13 +552,13 @@ hdb_dn2id_delete(
        DBT             key, data;
        DBC     *cursor;
        diskNode *d;
-       int rc, nrlen;
+       int rc;
        ID      nid;
+       unsigned char dlen[2];
 
        DBTzero(&key);
        key.size = sizeof(ID);
        key.ulen = key.size;
-       key.data = &nid;
        key.flags = DB_DBT_USERMEM;
        BDB_ID2DISK( eip->bei_id, &nid );
 
@@ -564,22 +568,32 @@ hdb_dn2id_delete(
        data.dlen = data.size;
        data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
 
+       /* Delete IDL cache entries */
        if ( bdb->bi_idl_cache_size ) {
+               /* Ours */
+               key.data = &e->e_id;
+               bdb_idl_cache_del( bdb, db, &key );
+               /* Parent's */
+               key.data = &eip->bei_id;
                bdb_idl_cache_del( bdb, db, &key );
        }
+       key.data = &nid;
        rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
        if ( rc ) return rc;
 
        d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
        d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff;
        d->nrdnlen[0] = (BEI(e)->bei_nrdn.bv_len >> 8) | 0x80;
+       dlen[0] = d->nrdnlen[0];
+       dlen[1] = d->nrdnlen[1];
        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_RANGE | DB_RMW );
+       rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE );
        if ( rc == 0 ) {
-               if ( !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val ))
+               if ( dlen[1] == d->nrdnlen[1] && dlen[0] == d->nrdnlen[0] &&
+                       !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val ))
                        rc = cursor->c_del( cursor, 0 );
                else
                        rc = DB_NOTFOUND;
@@ -591,7 +605,7 @@ hdb_dn2id_delete(
         */
        if ( rc == 0 ) {
                BDB_ID2DISK( e->e_id, &nid );
-               rc = cursor->c_get( cursor, &key, &data, DB_SET | DB_RMW );
+               rc = cursor->c_get( cursor, &key, &data, DB_SET );
                if ( rc == 0 )
                        rc = cursor->c_del( cursor, 0 );
        }
@@ -616,7 +630,8 @@ hdb_dn2id(
        int             rc = 0, nrlen;
        diskNode *d;
        char    *ptr;
-       ID idp;
+       unsigned char dlen[2];
+       ID idp, parentID;
 
        nrlen = dn_rdnlen( op->o_bd, in );
        if (!nrlen) nrlen = in->bv_len;
@@ -626,7 +641,8 @@ hdb_dn2id(
        key.data = &idp;
        key.ulen = sizeof(ID);
        key.flags = DB_DBT_USERMEM;
-       BDB_ID2DISK( ei->bei_parent->bei_id, &idp );
+       parentID = ( ei->bei_parent != NULL ) ? ei->bei_parent->bei_id : 0;
+       BDB_ID2DISK( parentID, &idp );
 
        DBTzero(&data);
        data.size = sizeof(diskNode) + nrlen - sizeof(ID) - 1;
@@ -640,21 +656,24 @@ hdb_dn2id(
        d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
        d->nrdnlen[1] = nrlen & 0xff;
        d->nrdnlen[0] = (nrlen >> 8) | 0x80;
+       dlen[0] = d->nrdnlen[0];
+       dlen[1] = d->nrdnlen[1];
        ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
        *ptr = '\0';
        data.data = d;
 
        rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE );
-       if ( rc == 0 && strncmp( d->nrdn, in->bv_val, nrlen )) {
+       if ( rc == 0 && (dlen[1] != d->nrdnlen[1] || dlen[0] != d->nrdnlen[0] ||
+               strncmp( d->nrdn, in->bv_val, nrlen ))) {
                rc = DB_NOTFOUND;
        }
        if ( rc == 0 ) {
-               ptr = data.data + data.size - sizeof(ID);
+               ptr = (char *) data.data + data.size - sizeof(ID);
                BDB_DISK2ID( ptr, &ei->bei_id );
                ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
                ptr = d->nrdn + nrlen + 1;
                ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
-               if ( !ei->bei_parent->bei_dkids ) {
+               if ( ei->bei_parent != NULL && !ei->bei_parent->bei_dkids ) {
                        db_recno_t dkids;
                        /* How many children does the parent have? */
                        /* FIXME: do we need to lock the parent
@@ -684,7 +703,6 @@ hdb_dn2id_parent(
        int             rc = 0;
        diskNode *d;
        char    *ptr;
-       unsigned char *pt2;
        ID      nid;
 
        DBTzero(&key);
@@ -710,7 +728,7 @@ hdb_dn2id_parent(
                        rc = LDAP_OTHER;
                } else {
                        db_recno_t dkids;
-                       ptr = data.data + data.size - sizeof(ID);
+                       ptr = (char *) data.data + data.size - sizeof(ID);
                        BDB_DISK2ID( ptr, idp );
                        ei->bei_nrdn.bv_len = (d->nrdnlen[0] << 8) | d->nrdnlen[1];
                        ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
@@ -800,12 +818,13 @@ struct dn2id_cookie {
        ID dbuf;
        ID *ids;
        void *ptr;
-       ID tmp[BDB_IDL_DB_SIZE];
+       ID *tmp;
        ID *buf;
        DBT key;
        DBT data;
        DBC *dbc;
        Operation *op;
+       int need_sort;
 };
 
 static int
@@ -816,7 +835,7 @@ apply_func(
        EntryInfo *ei = data;
        ID *idl = arg;
 
-       bdb_idl_insert( idl, ei->bei_id );
+       bdb_idl_append_one( idl, ei->bei_id );
        return 0;
 }
 
@@ -825,6 +844,16 @@ hdb_dn2idl_internal(
        struct dn2id_cookie *cx
 )
 {
+       BDB_IDL_ZERO( cx->tmp );
+
+       if ( !cx->ei ) {
+               cx->ei = bdb_cache_find_info( cx->bdb, cx->id );
+               if ( !cx->ei ) {
+                       cx->rc = DB_NOTFOUND;
+                       goto saveit;
+               }
+       }
+
        if ( cx->bdb->bi_idl_cache_size ) {
                cx->key.data = &cx->id;
                cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
@@ -835,15 +864,6 @@ hdb_dn2idl_internal(
                        goto gotit;
                }
        }
-       BDB_IDL_ZERO( cx->tmp );
-
-       if ( !cx->ei ) {
-               cx->ei = bdb_cache_find_info( cx->bdb, cx->id );
-               if ( !cx->ei ) {
-                       cx->rc = DB_NOTFOUND;
-                       goto saveit;
-               }
-       }
 
        bdb_cache_entryinfo_lock( cx->ei );
 
@@ -910,7 +930,7 @@ hdb_dn2idl_internal(
                                        ei.bei_rdn.bv_len = len - sizeof(diskNode)
                                                - ei.bei_nrdn.bv_len;
                                        ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
-                                       bdb_idl_insert( cx->tmp, ei.bei_id );
+                                       bdb_idl_append_one( cx->tmp, ei.bei_id );
                                        hdb_cache_load( cx->bdb, &ei, &ei2 );
                                }
                        }
@@ -932,24 +952,25 @@ hdb_dn2idl_internal(
        }
 
 saveit:
+       if ( !BDB_IDL_IS_RANGE( cx->tmp ) && cx->tmp[0] > 3 )
+               bdb_idl_sort( cx->tmp, cx->buf );
        if ( cx->bdb->bi_idl_cache_max_size ) {
                cx->key.data = &cx->id;
                bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
        }
-       ;
+
 gotit:
        if ( !BDB_IDL_IS_ZERO( cx->tmp )) {
                if ( cx->prefix == DN_SUBTREE_PREFIX ) {
-                       if (cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS) {
-                               bdb_idl_union( cx->ids, cx->tmp );
-                       } else {
+                       bdb_idl_append( cx->ids, cx->tmp );
+                       cx->need_sort = 1;
+                       if ( !(cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS)) {
                                ID *save, idcurs;
                                EntryInfo *ei = cx->ei;
                                int nokids = 1;
                                save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
                                        cx->op->o_tmpmemctx );
                                BDB_IDL_CPY( save, cx->tmp );
-                               bdb_idl_union( cx->ids, cx->tmp );
 
                                idcurs = 0;
                                for ( cx->id = bdb_idl_first( save, &idcurs );
@@ -1002,11 +1023,13 @@ hdb_dn2idl(
        cx.ei = e->e_id ? BEI(e) : &bdb->bi_cache.c_dntree;
        cx.bdb = bdb;
        cx.db = cx.bdb->bi_dn2id->bdi_db;
-       cx.prefix = op->ors_scope == LDAP_SCOPE_ONELEVEL
-               DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
+       cx.prefix = (op->ors_scope == LDAP_SCOPE_ONELEVEL) ?
+               DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
        cx.ids = ids;
-       cx.buf = stack;
+       cx.tmp = stack;
+       cx.buf = stack + BDB_IDL_UM_SIZE;
        cx.op = op;
+       cx.need_sort = 0;
 
        BDB_IDL_ZERO( ids );
        if ( cx.prefix == DN_SUBTREE_PREFIX ) {
@@ -1020,6 +1043,10 @@ hdb_dn2idl(
 
        DBTzero(&cx.data);
 
-       return hdb_dn2idl_internal(&cx);
+       hdb_dn2idl_internal(&cx);
+       if ( cx.need_sort && !BDB_IDL_IS_RANGE( cx.ids ) && cx.ids[0] > 3 )
+               bdb_idl_sort( cx.ids, cx.tmp );
+
+       return cx.rc;
 }
 #endif /* BDB_HIER */