]> git.sur5r.net Git - openldap/commitdiff
Some fixes for BDB_IDL_MULTI. Experimental back-hdb code.
authorHoward Chu <hyc@openldap.org>
Fri, 7 Dec 2001 12:38:25 +0000 (12:38 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 7 Dec 2001 12:38:25 +0000 (12:38 +0000)
servers/slapd/back-bdb/back-bdb.h
servers/slapd/back-bdb/dbcache.c
servers/slapd/back-bdb/dn2id.c
servers/slapd/back-bdb/id2entry.c
servers/slapd/back-bdb/idl.c
servers/slapd/back-bdb/init.c
servers/slapd/back-bdb/tools.c

index d9b38e4399688aa568e3966fc94424485d8ed249..1f7b3f25791b8f42a14c2cfc4e9d02aa5cfbfcfc 100644 (file)
@@ -16,7 +16,8 @@
 LDAP_BEGIN_DECL
 
 #define BDB_FILTER_INDICES 1
-#define BDB_IDL_MULTI          1
+/* #define BDB_IDL_MULTI               1 */
+/* #define BDB_HIER            1 */
 
 #define DN_BASE_PREFIX         SLAP_INDEX_EQUALITY_PREFIX
 #define DN_ONE_PREFIX          '%'
@@ -32,7 +33,11 @@ LDAP_BEGIN_DECL
 
 #define BDB_TXN_RETRIES        16
 
+#ifdef BDB_HIER
+#define BDB_DBENV_HOME LDAP_RUNDIR LDAP_DIRSEP "openldap-hdb"
+#else
 #define BDB_DBENV_HOME LDAP_RUNDIR LDAP_DIRSEP "openldap-bdb"
+#endif
 
 #ifdef BDB_SUBDIRS
 #define BDB_TMP_SUBDIR LDAP_DIRSEP "tmp"
@@ -42,7 +47,11 @@ 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
@@ -50,7 +59,7 @@ LDAP_BEGIN_DECL
  * fit into a single database page, more is better. 64K is BDB's
  * upper bound. The same issues arise with IDLs in the index databases,
  * but it's nearly impossible to avoid overflows there.
- * 
+ *
  * When using BDB_IDL_MULTI, the IDL size is no longer an issue. Smaller
  * pages are better for concurrency.
  */
@@ -89,6 +98,14 @@ struct bdb_info {
 
        slap_mask_t     bi_defaultmask;
        Avlnode         *bi_attrs;
+#ifdef BDB_HIER
+       Avlnode         *bi_tree;
+       ldap_pvt_thread_rdwr_t  bi_tree_rdwr;
+       void            *bi_troot;
+       int             bi_nrdns;
+       int             bi_sufflen;
+       int             bi_nsufflen;
+#endif
 
        int             bi_txn;
        int                     bi_txn_cp;
@@ -106,7 +123,11 @@ struct bdb_info {
 };
 
 #define bi_id2entry    bi_databases[BDB_ID2ENTRY]
+#ifdef BDB_HIER
+#define bi_id2parent   bi_databases[BDB_ID2PARENT]
+#else
 #define bi_dn2id       bi_databases[BDB_DN2ID]
+#endif
 
 struct bdb_op_info {
        BackendDB*      boi_bdb;
index 3156408e41af3895c7562e06d10e8c529b9caf25..9fefd7f287a7e21661621a29d9aed17b5208d010 100644 (file)
@@ -70,7 +70,7 @@ bdb_db_cache(
 
        rc = db->bdi_db->set_pagesize( db->bdi_db, BDB_PAGESIZE );
 #ifdef BDB_IDL_MULTI
-       rc = db->bdi_db->set_flags( db->bdi_db, DB_DUPSORT );
+       rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT );
        rc = db->bdi_db->set_dup_compare( db->bdi_db, bdb_bt_compare );
 #endif
 
index 1021446c93e272047fda6cf50f8c35ce0e12bc62..a40663cbaef200791df9cc712a0f8df6e3e95535 100644 (file)
@@ -13,6 +13,7 @@
 #include "back-bdb.h"
 #include "idl.h"
 
+#ifndef BDB_HIER
 int
 bdb_dn2id_add(
        BackendDB       *be,
@@ -73,7 +74,7 @@ bdb_dn2id_add(
                        int i;
                        ((char *)key.data)[0] = DN_SUBTREE_PREFIX;
                        for( i=0; subtree[i] != NULL; i++ ) {
-                               if (be_issuffix(be, subtree[i]))
+                               if( be_issuffix( be, subtree[i] ))
                                        continue;
                                key.size = strlen( subtree[i] ) + 2;
                                AC_MEMCPY( &((char *)key.data)[1],
@@ -391,3 +392,527 @@ bdb_dn2idl(
        ch_free( key.data );
        return rc;
 }
+#else  /* BDB_HIER */
+
+/* Experimental management routines for a hierarchically structured backend.
+ *
+ * Unsupported! Use at your own risk!
+ *
+ * Instead of a dn2id database, we use an id2parent database. Each entry in
+ * this database is a struct diskNode, containing the ID of the node's parent
+ * and the RDN of the node.
+ */
+typedef struct diskNode {
+       ID parent;
+       struct berval rdn;
+       struct berval nrdn;
+} diskNode;
+
+/* In bdb_db_open() we call bdb_build_tree() which reads the entire id2parent
+ * database into memory (into an AVL tree). Next we iterate through each node
+ * of this tree, connecting each child to its parent. The nodes in this AVL
+ * tree are a struct idNode. The immediate (Onelevel) children of a node are
+ * referenced in the i_kids AVL tree. With this arrangement, there is no need
+ * to maintain the DN_ONE_PREFIX or DN_SUBTREE_PREFIX database keys. Note that
+ * the DN of an entry is constructed by walking up the list of i_parent
+ * pointers, so no full DN is stored on disk anywhere. This makes modrdn
+ * extremely efficient, even when operating on a populated subtree.
+ *
+ * The idNode tree is searched directly from the root when performing id to
+ * entry lookups. The tree is traversed using the i_kids subtrees when
+ * performing dn to id lookups.
+ */
+typedef struct idNode {
+       ID i_id;
+       struct idNode *i_parent;
+       diskNode *i_rdn;
+       Avlnode *i_kids;
+       ldap_pvt_thread_rdwr_t i_kids_rdwr;
+} idNode;
+
+/* strcopy is like strcpy except it returns a pointer to the trailing NUL of
+ * the result string. This allows fast construction of catenated strings
+ * without the overhead of strlen/strcat.
+ */
+char *
+bdb_strcopy(
+       char *a,
+       char *b
+)
+{
+       if (!a || !b)
+               return a;
+       
+       while (*a++ = *b++) ;
+       return a-1;
+}
+
+/* The main AVL tree is sorted in ID order. The i_kids AVL trees are
+ * sorted in lexical order. These are the various helper routines used
+ * for the searches and sorts.
+ */
+static int
+node_find_cmp(
+       ID id,
+       idNode *n
+)
+{
+       return id - n->i_id;
+}
+
+static int
+node_frdn_cmp(
+       char *nrdn,
+       idNode *n
+)
+{
+       return strcmp(nrdn, n->i_rdn->nrdn.bv_val);
+}
+
+static int
+node_add_cmp(
+       idNode *a,
+       idNode *b
+)
+{
+       return a->i_id - b->i_id;
+}
+
+static int
+node_rdn_cmp(
+       idNode *a,
+       idNode *b
+)
+{
+       return strcmp(a->i_rdn->nrdn.bv_val, b->i_rdn->nrdn.bv_val);
+}
+
+idNode * bdb_find_id_node(
+       ID id,
+       Avlnode *tree
+)
+{
+       return avl_find(tree, (const void *)id, (AVL_CMP)node_find_cmp);
+}
+
+idNode * bdb_find_rdn_node(
+       char *nrdn,
+       Avlnode *tree
+)
+{
+       return avl_find(tree, (const void *)nrdn, (AVL_CMP)node_frdn_cmp);
+}
+
+/* This function links a node into its parent's i_kids tree. */
+int bdb_insert_kid(
+       idNode *a,
+       Avlnode *tree
+)
+{
+       int rc;
+
+       if (a->i_rdn->parent == 0)
+               return 0;
+       a->i_parent = bdb_find_id_node(a->i_rdn->parent, tree);
+       if (!a->i_parent)
+               return -1;
+       ldap_pvt_thread_rdwr_wlock(&a->i_parent->i_kids_rdwr);
+       rc = avl_insert( &a->i_parent->i_kids, (caddr_t) a,
+               (AVL_CMP)node_rdn_cmp, (AVL_DUP) avl_dup_error );
+       ldap_pvt_thread_rdwr_wunlock(&a->i_parent->i_kids_rdwr);
+       return rc;
+}
+
+/* This function adds a node into the main AVL tree */
+idNode *bdb_add_node(
+       ID id,
+       char *d,
+       struct bdb_info *bdb
+)
+{
+       idNode *node;
+
+       node = (idNode *)ch_malloc(sizeof(idNode));
+       node->i_id = id;
+       node->i_parent = NULL;
+       node->i_kids = NULL;
+       node->i_rdn = (diskNode *)d;
+       node->i_rdn->rdn.bv_val += (long)d;
+       node->i_rdn->nrdn.bv_val += (long)d;
+       ldap_pvt_thread_rdwr_init(&node->i_kids_rdwr);
+       avl_insert( &bdb->bi_tree, (caddr_t) node,
+                       (AVL_CMP)node_add_cmp, (AVL_DUP) avl_dup_error );
+       if (id == 1)
+               bdb->bi_troot = node;
+       return node;
+}
+
+/* This function initializes the trees at startup time. */
+int bdb_build_tree(
+       Backend *be
+)
+{
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       int i, rc;
+       DBC *cursor;
+       DBT key, data;
+       ID id;
+       idNode *node;
+       char **rdns;
+
+       bdb->bi_tree = NULL;
+
+       rc = bdb->bi_id2parent->bdi_db->cursor(
+               bdb->bi_id2parent->bdi_db, NULL, &cursor,
+               bdb->bi_db_opflags );
+       if( rc != 0 ) {
+               return NOID;
+       }
+
+       /* When be_suffix is turned into struct berval or LDAPDN
+        * life will get a lot easier... Since no DNs live on disk, we
+        * need to operate on the be_suffix to fully qualify our DNs.
+        * We need to know how many components are in the suffix DN,
+        * so we can tell where the suffix ends and our nodes begin.
+        *
+        * Note that this code always uses be_suffix[0], so defining
+        * multiple suffixes for a single backend won't work!
+        */
+       bdb->bi_sufflen = strlen(be->be_suffix[0]);
+       bdb->bi_nsufflen = strlen(be->be_nsuffix[0]);
+
+       rdns = ldap_explode_dn(be->be_nsuffix[0], 0);
+       for (i=0; rdns[i]; i++);
+       bdb->bi_nrdns = i;
+       charray_free(rdns);
+
+       DBTzero( &key );
+       DBTzero( &data );
+       key.data = (char *)&id;
+       key.ulen = sizeof( id );
+       key.flags = DB_DBT_USERMEM;
+       data.flags = DB_DBT_MALLOC;
+
+       while (cursor->c_get( cursor, &key, &data, DB_NEXT ) == 0) {
+               bdb_add_node( id, data.data, bdb );
+       }
+       cursor->c_close( cursor );
+
+       rc = avl_apply(bdb->bi_tree, (AVL_APPLY)bdb_insert_kid, bdb->bi_tree,
+               -1, AVL_INORDER );
+
+       return rc;
+}
+
+/* This function constructs a full DN for a given id. We really should
+ * be passing idNodes directly, to save some effort...
+ */
+int bdb_fix_dn(
+       BackendDB *be,
+       ID id,
+       Entry *e
+)
+{
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       idNode *n, *o;
+       int rlen, nrlen;
+       char *ptr, *nptr;
+       
+       ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
+       o = bdb_find_id_node(id, bdb->bi_tree);
+       rlen = bdb->bi_sufflen + 1;
+       nrlen = bdb->bi_nsufflen + 1;
+       for (n = o; n; n=n->i_parent) {
+               rlen += n->i_rdn->rdn.bv_len + 1;
+               nrlen += n->i_rdn->nrdn.bv_len + 1;
+       }
+       e->e_dn = ch_malloc(rlen + nrlen);
+       e->e_ndn = e->e_dn + rlen;
+       ptr = e->e_dn;
+       nptr = e->e_ndn;
+       for (n = o; n; n=n->i_parent) {
+               ptr = bdb_strcopy(ptr, n->i_rdn->rdn.bv_val);
+               *ptr++ = ',';
+               nptr = bdb_strcopy(nptr, n->i_rdn->nrdn.bv_val);
+               *nptr++ = ',';
+       }
+       ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
+
+       ptr--;
+       nptr--;
+       strcpy(ptr, be->be_suffix[0]);
+       strcpy(nptr, be->be_nsuffix[0]);
+
+       return 0;
+}
+
+int
+bdb_dn2id_add(
+       BackendDB       *be,
+       DB_TXN *txn,
+       const char      *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;
+       char            *nrdn = dn_rdn( be, e->e_ndn );
+       char            *rdn;
+       diskNode *d;
+       idNode *n;
+
+       if (nrdn == NULL) {
+               nrdn = "";
+               rdn = "";
+       } else {
+               rdn = dn_rdn( be, e->e_dn );
+       }
+
+       nrlen = strlen(nrdn);
+       rlen = strlen(rdn);
+       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 = bdb_strcopy(d->rdn.bv_val, rdn) + 1;
+       strcpy(d->nrdn.bv_val, nrdn);
+       d->rdn.bv_val -= (long)d;
+       d->nrdn.bv_val -= (long)d;
+
+       if (nrdn[0]) free(nrdn);
+       if (rdn[0]) free(rdn);
+
+       if (pdn) {
+               bdb_dn2id(be, txn, pdn, &d->parent);
+       } 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;
+}
+
+int
+bdb_dn2id_delete(
+       BackendDB       *be,
+       DB_TXN *txn,
+       const char      *pdn,
+       const char      *dn,
+       ID              id )
+{
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       int rc;
+       DBT             key;
+       DB *db = bdb->bi_id2parent->bdi_db;
+       idNode *n;
+
+       DBTzero(&key);
+       key.size = sizeof(id);
+       key.data = &id;
+
+       rc = db->del( db, txn, &key, 0);
+
+       ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr);
+       n = avl_delete(&bdb->bi_tree, (void *)id, (AVL_CMP)node_find_cmp);
+       if (n) {
+               if (n->i_parent) {
+                       ldap_pvt_thread_rdwr_wlock(&n->i_parent->i_kids_rdwr);
+                       avl_delete(&n->i_parent->i_kids, n->i_rdn->nrdn.bv_val,
+                               (AVL_CMP)node_frdn_cmp);
+                       ldap_pvt_thread_rdwr_wunlock(&n->i_parent->i_kids_rdwr);
+               }
+               free(n->i_rdn);
+               ldap_pvt_thread_rdwr_destroy(&n->i_kids_rdwr);
+               free(n);
+       }
+       if (id == 1)
+               bdb->bi_troot = NULL;
+       ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr);
+
+       return rc;
+}
+
+int
+bdb_dn2id_matched(
+       BackendDB       *be,
+       DB_TXN *txn,
+       const char      *in,
+       ID *id,
+       char **matchedDN )
+{
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       int             i;
+       char            **rdns;
+       idNode *n, *p;
+
+       if (!bdb->bi_troot)
+               return DB_NOTFOUND;
+
+       p = bdb->bi_troot;
+       if (be_issuffix(be, in)) {
+               *id = p->i_id;
+               return 0;
+       }
+
+       rdns = ldap_explode_dn(in, 0);
+       for (i=0; rdns[i]; i++);
+       i -= bdb->bi_nrdns;
+       if (i < 0)
+               return -1;
+       n = p;
+       ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
+       for (--i; i>=0; i--) {
+               ldap_pvt_thread_rdwr_rlock(&p->i_kids_rdwr);
+               n = bdb_find_rdn_node(rdns[i], p->i_kids);
+               ldap_pvt_thread_rdwr_runlock(&p->i_kids_rdwr);
+               if (!n) break;
+               p = n;
+       }
+       ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
+
+       if (n) {
+               *id = n->i_id;
+       } else if (matchedDN) {
+               int len = 0, j;
+               char *ptr;
+               ++i;
+               for (j=i; rdns[j]; j++)
+                       len += strlen(rdns[j]) + 1;
+               ptr = ch_malloc(len);
+               *matchedDN = ptr;
+               for (;rdns[i]; i++) {
+                       ptr = bdb_strcopy(ptr, rdns[i]);
+                       *ptr++ = ',';
+               }
+               ptr[-1] = '\0';
+       }
+       return n ? 0 : DB_NOTFOUND;
+}
+
+int
+bdb_dn2id(
+       BackendDB       *be,
+       DB_TXN *txn,
+       const char      *dn,
+       ID *id )
+{
+       return bdb_dn2id_matched(be, txn, dn, id, NULL);
+}
+
+int
+bdb_dn2id_children(
+       BackendDB       *be,
+       DB_TXN *txn,
+       const char *dn )
+{
+       int             rc;
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       ID              id;
+       idNode *n;
+
+       rc = bdb_dn2id(be, txn, dn, &id);
+       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;
+}
+
+/* Since we don't store IDLs for onelevel or subtree, we have to construct
+ * them on the fly... Perhaps the i_kids tree ought to just be an IDL?
+ */
+static int
+insert_one(
+       idNode *n,
+       ID *ids
+)
+{
+       return bdb_idl_insert(ids, n->i_id);
+}
+
+static int
+insert_sub(
+       idNode *n,
+       ID *ids
+)
+{
+       int rc;
+
+       rc = bdb_idl_insert(ids, n->i_id);
+       if (rc == 0) {
+               ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr);
+               rc = avl_apply(n->i_kids, (AVL_APPLY)insert_sub, ids, -1,
+                       AVL_INORDER);
+               ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
+       }
+       return rc;
+}
+
+int
+bdb_dn2idl(
+       BackendDB       *be,
+       const char      *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);
+       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, (AVL_APPLY)insert_one, ids, -1,
+                       AVL_INORDER);
+       } else {
+               rc = avl_apply(n->i_kids, (AVL_APPLY)insert_sub, ids, -1,
+                       AVL_INORDER);
+       }
+       ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
+       return rc;
+}
+#endif /* BDB_HIER */
index e4851b9c1b60797c1a3359a66d325e2ab46b0a6d..eb40b6bac727f0dfbc263a0309f9adb0139cba69 100644 (file)
@@ -23,12 +23,23 @@ int bdb_id2entry_put(
        DBT key, data;
        struct berval bv;
        int rc;
+#ifdef BDB_HIER
+       char *odn, *ondn;
 
+       /* We only store rdns, and they go in the id2parent database. */
+
+       odn = e->e_dn; ondn = e->e_ndn;
+
+       e->e_dn = ""; e->e_ndn = "";
+#endif
        DBTzero( &key );
        key.data = (char *) &e->e_id;
        key.size = sizeof(ID);
 
        rc = entry_encode( e, &bv );
+#ifdef BDB_HIER
+       e->e_dn = odn; e->e_ndn = ondn;
+#endif
        if( rc != LDAP_SUCCESS ) {
                return -1;
        }
@@ -47,7 +58,7 @@ int bdb_id2entry_add(
        DB_TXN *tid,
        Entry *e )
 {
-       return bdb_id2entry_put( be, tid, e, DB_NOOVERWRITE );
+       return bdb_id2entry_put(be, tid, e, DB_NOOVERWRITE);
 }
 
 int bdb_id2entry_update(
@@ -55,7 +66,7 @@ int bdb_id2entry_update(
        DB_TXN *tid,
        Entry *e )
 {
-       return bdb_id2entry_put( be, tid, e, 0 );
+       return bdb_id2entry_put(be, tid, e, 0);
 }
 
 int bdb_id2entry(
@@ -98,6 +109,9 @@ int bdb_id2entry(
                 */
                ch_free( data.data );
        }
+#ifdef BDB_HIER
+       bdb_fix_dn(be, id, *e);
+#endif
        return rc;
 }
 
@@ -143,6 +157,7 @@ int bdb_entry_return(
 
        return 0;
 }
+
 int bdb_entry_release(
        BackendDB *be,
        Connection *c,
index ef0889b0d71728931ac73b09c41eea15e6fe8b27..2fb1bef89169376bc401ba0918fd48ad7a1a92ef 100644 (file)
@@ -75,7 +75,7 @@ unsigned bdb_idl_search( ID *ids, ID id )
         */
        unsigned base = 0;
        unsigned cursor = 0;
-       int val;
+       int val = 0;
        unsigned n = ids[0];
 
 #if IDL_DEBUG > 0
@@ -123,7 +123,7 @@ unsigned bdb_idl_search( ID *ids, ID id )
 #endif
 }
 
-static int idl_insert( ID *ids, ID id )
+int bdb_idl_insert( ID *ids, ID id )
 {
        unsigned x = bdb_idl_search( ids, id );
 
@@ -316,6 +316,17 @@ bdb_idl_insert_key(
 
        DBTzero( &data );
 #ifdef BDB_IDL_MULTI
+       /* FIXME: We really ought to count how many data items currently exist
+        * for this key, and cap off with a range when we hit the max. We need
+        * to use a 0 in the first slot to denote a range - since the data are
+        * sorted in ascending order, the only way to get a flag into the
+        * first slot is to use the smallest possible ID value. The fetch
+        * function above can turn it into a "memory-format" range. We also
+        * have to delete all of the existing data items when converting from
+        * a list to a range. And of course, if it's already a range, we need
+        * to read it in and process it instead of just doing the blind put
+        * that we do right now...
+        */
        data.data = &id;
        data.size = sizeof(id);
        data.flags = DB_DBT_USERMEM;
@@ -364,7 +375,7 @@ bdb_idl_insert_key(
                }
 
        } else {
-               rc = idl_insert( ids, id );
+               rc = bdb_idl_insert( ids, id );
 
                if( rc == -1 ) {
                        Debug( LDAP_DEBUG_TRACE, "=> bdb_idl_insert_key: dup\n",
@@ -373,7 +384,7 @@ bdb_idl_insert_key(
                }
                if( rc != 0 ) {
                        Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
-                               "idl_insert failed (%d)\n",
+                               "bdb_idl_insert failed (%d)\n",
                                rc, 0, 0 );
                        
                        return rc;
index 41e4c37b77ee83456dfc2558ac76fee343bddad2..490baca03903a379b19232514384e50c0034f358 100644 (file)
@@ -20,7 +20,11 @@ static struct bdbi_database {
        int flags;
 } bdbi_databases[] = {
        { "id2entry" BDB_SUFFIX, "id2entry", DB_BTREE, 0 },
+#ifdef BDB_HIER
+       { "id2parent" BDB_SUFFIX, "id2parent", DB_BTREE, 0 },
+#else
        { "dn2id" BDB_SUFFIX, "dn2id", DB_BTREE, 0 },
+#endif
        { NULL, NULL, 0, 0 }
 };
 
@@ -73,6 +77,9 @@ bdb_db_init( BackendDB *be )
 
        ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
        ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
+#ifdef BDB_HIER
+       ldap_pvt_thread_rdwr_init( &bdb->bi_tree_rdwr );
+#endif
 
        be->be_private = bdb;
        return 0;
@@ -247,16 +254,19 @@ bdb_db_open( BackendDB *be )
                        rc = db->bdi_db->set_pagesize( db->bdi_db,
                                BDB_ID2ENTRY_PAGESIZE );
                } else {
-                       rc = db->bdi_db->set_pagesize( db->bdi_db,
-                               BDB_PAGESIZE );
-               }
-#ifdef BDB_IDL_MULTI
-               if( i == BDB_DN2ID ) {
-                       rc = db->bdi_db->set_flags( db->bdi_db, DB_DUPSORT );
+#ifdef BDB_HIER
+                       rc = db->bdi_db->set_bt_compare( db->bdi_db,
+                               bdb_bt_compare );
+#elif defined(BDB_IDL_MULTI)
+                       rc = db->bdi_db->set_flags( db->bdi_db, 
+                               DB_DUP | DB_DUPSORT );
                        rc = db->bdi_db->set_dup_compare( db->bdi_db,
                                bdb_bt_compare );
-               }
 #endif
+                       rc = db->bdi_db->set_pagesize( db->bdi_db,
+                               BDB_PAGESIZE );
+               }
+
                rc = db->bdi_db->open( db->bdi_db,
                        bdbi_databases[i].file,
                /*      bdbi_databases[i].name, */ NULL,
@@ -288,6 +298,9 @@ bdb_db_open( BackendDB *be )
        }
 
        /* <insert> open (and create) index databases */
+#ifdef BDB_HIER
+       rc = bdb_build_tree( be );
+#endif
 
 #ifndef NO_THREADS
        if( bdb->bi_lock_detect != DB_LOCK_NORUN ) {
index b85862e5fdb33dd330d7e8ed6391c5bce7ad6643..5001506612ce6877a7ebaea256a963c0185ecb9f 100644 (file)
@@ -103,6 +103,10 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
                e->e_id = id;
        }
 
+#ifdef BDB_HIER
+       bdb_fix_dn(be, id, e);
+#endif
+
        return e;
 }