| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024 | 
							- /** BEGIN COPYRIGHT BLOCK
 
-  * This Program is free software; you can redistribute it and/or modify it under
 
-  * the terms of the GNU General Public License as published by the Free Software
 
-  * Foundation; version 2 of the License.
 
-  * 
 
-  * This Program is distributed in the hope that it will be useful, but WITHOUT
 
-  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
-  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
-  * 
 
-  * You should have received a copy of the GNU General Public License along with
 
-  * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
-  * Place, Suite 330, Boston, MA 02111-1307 USA.
 
-  * 
 
-  * In addition, as a special exception, Red Hat, Inc. gives You the additional
 
-  * right to link the code of this Program with code not covered under the GNU
 
-  * General Public License ("Non-GPL Code") and to distribute linked combinations
 
-  * including the two, subject to the limitations in this paragraph. Non-GPL Code
 
-  * permitted under this exception must only link to the code of this Program
 
-  * through those well defined interfaces identified in the file named EXCEPTION
 
-  * found in the source code files (the "Approved Interfaces"). The files of
 
-  * Non-GPL Code may instantiate templates or use macros or inline functions from
 
-  * the Approved Interfaces without causing the resulting work to be covered by
 
-  * the GNU General Public License. Only Red Hat, Inc. may make changes or
 
-  * additions to the list of Approved Interfaces. You must obey the GNU General
 
-  * Public License in all respects for all of the Program code and other code used
 
-  * in conjunction with the Program except the Non-GPL Code covered by this
 
-  * exception. If you modify this file, you may extend this exception to your
 
-  * version of the file, but you are not obligated to do so. If you do not wish to
 
-  * provide this exception without modification, you must delete this exception
 
-  * statement from your version and license this file solely under the GPL without
 
-  * exception. 
 
-  * 
 
-  * 
 
-  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
 
-  * Copyright (C) 2005 Red Hat, Inc.
 
-  * All rights reserved.
 
-  * END COPYRIGHT BLOCK **/
 
- #ifdef HAVE_CONFIG_H
 
- #  include <config.h>
 
- #endif
 
- #include "back-ldbm.h"
 
- static char *sourcefile = LDBM_ANCESTORID_STR;
 
- /* Start of definitions for a simple cache using a hash table */
 
- typedef struct id2idl {
 
-     ID keyid;
 
-     IDList *idl;
 
-     struct id2idl *next;
 
- } id2idl;
 
- static void id2idl_free(id2idl **ididl);
 
- static int id2idl_same_key(const void *ididl, const void *k);
 
- typedef Hashtable id2idl_hash;
 
- #define id2idl_new_hash(size) new_hash(size,HASHLOC(id2idl,next),NULL,id2idl_same_key)
 
- #define id2idl_hash_lookup(ht,key,he) find_hash(ht,key,sizeof(ID),(void**)(he))
 
- #define id2idl_hash_add(ht,key,he,alt) add_hash(ht,key,sizeof(ID),he,(void**)(alt))
 
- #define id2idl_hash_remove(ht,key) remove_hash(ht,key,sizeof(ID))
 
- static void id2idl_hash_destroy(id2idl_hash *ht);
 
- /* End of definitions for a simple cache using a hash table */
 
- static int ldbm_parentid(backend *be, DB_TXN *txn, ID id, ID *ppid);
 
- static int check_cache(id2idl_hash *ht);
 
- static IDList *idl_union_allids(backend *be, struct attrinfo *ai, IDList *a, IDList *b);
 
- static int ldbm_ancestorid_default_create_index(backend *be);
 
- static int ldbm_ancestorid_new_idl_create_index(backend *be);
 
- static int ldbm_get_nonleaf_ids(backend *be, DB_TXN *txn, IDList **idl)
 
- {
 
-     int ret = 0;
 
-     DB *db    = NULL;
 
-     DBC *dbc  = NULL; 
 
-     DBT key  = {0};
 
-     DBT data = {0};
 
-     struct attrinfo *ai = NULL;
 
-     IDList *nodes = NULL;
 
-     ID id;
 
-     /* Open the parentid index */
 
-     ainfo_get( be, LDBM_PARENTID_STR, &ai );
 
-     /* Open the parentid index file */
 
-     ret = dblayer_get_index_file(be, ai, &db, DBOPEN_CREATE);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13010,ret);
 
-         goto out;
 
-     }
 
-     /* Get a cursor so we can walk through the parentid */
 
-     ret = db->cursor(db,txn,&dbc,0);
 
-     if (ret != 0 ) {
 
-         ldbm_nasty(sourcefile,13020,ret);
 
-         goto out;
 
-     }
 
-     /* For each key which is an equality key */
 
-     do {
 
-         ret = dbc->c_get(dbc,&key,&data,DB_NEXT_NODUP);
 
-         if ((ret == 0) && (*(char*)key.data == EQ_PREFIX)) {
 
-             id = (ID) strtoul((char*)key.data+1, NULL, 10);
 
-             idl_insert(&nodes, id);
 
-         }
 
-     } while (ret == 0);
 
-     /* Check for success */
 
-     if (ret == DB_NOTFOUND) ret = 0;
 
-     if (ret != 0) ldbm_nasty(sourcefile,13030,ret);
 
-  out:
 
-     /* Close the cursor */
 
-     if (dbc != NULL) {
 
-         if (ret == 0) {
 
-             ret = dbc->c_close(dbc);
 
-             if (ret != 0) ldbm_nasty(sourcefile,13040,ret);
 
-         } else {
 
-             (void)dbc->c_close(dbc);
 
-         }
 
-     }
 
-     /* Release the parentid file */
 
-     if (db != NULL) {
 
-         dblayer_release_index_file( be, ai, db );
 
-     }
 
-     /* Return the idlist */
 
-     if (ret == 0) {
 
-         *idl = nodes;
 
-         LDAPDebug(LDAP_DEBUG_TRACE, "found %lu nodes for ancestorid\n", 
 
-                   (u_long)IDL_NIDS(nodes), 0, 0);
 
-     } else {
 
-         idl_free(&nodes);
 
-         *idl = NULL;
 
-     }
 
-     return ret;
 
- }
 
- /*
 
-  * XXX: This function creates ancestorid index, which is a sort of hack.
 
-  *      This function handles idl directly, 
 
-  *      which should have been implemented in the idl file(s).
 
-  *      When the idl code would be updated in the future,
 
-  *      this function may also get affected.
 
-  *      (see also bug#: 605535)
 
-  *
 
-  * Construct the ancestorid index. Requirements:
 
-  * - The backend is read only.
 
-  * - The parentid index is accurate.
 
-  * - Non-leaf entries have IDs less than their descendants
 
-  *   (guaranteed after a database import but not after a subtree move)
 
-  *
 
-  */
 
- int ldbm_ancestorid_create_index(backend *be)
 
- {
 
- 	return (idl_get_idl_new()) ?
 
- 		ldbm_ancestorid_new_idl_create_index(be) :
 
- 	    ldbm_ancestorid_default_create_index(be);
 
- }
 
- /*
 
-  * Create the ancestorid index.  This version is safe to
 
-  * use whichever IDL mode is active.  However, it may be
 
-  * quite a bit slower than ldbm_ancestorid_new_idl_create_index()
 
-  * when the new mode is used, particularly with large databases.
 
-  */
 
- static int ldbm_ancestorid_default_create_index(backend *be)
 
- {
 
-     int ret = 0;
 
-     DB *db_pid    = NULL;
 
-     DB *db_aid    = NULL;
 
-     DBT key  = {0};
 
-     DB_TXN *txn = NULL;
 
-     struct attrinfo *ai_pid = NULL;
 
-     struct attrinfo *ai_aid = NULL;
 
-     char keybuf[24];
 
-     IDList *nodes = NULL;
 
-     IDList *children = NULL, *descendants = NULL;
 
-     NIDS nids;
 
-     ID id, parentid;
 
-     id2idl_hash *ht = NULL;
 
-     id2idl *ididl;
 
-     /*
 
-      * We need to iterate depth-first through the non-leaf nodes
 
-      * in the tree amassing an idlist of descendant ids for each node.
 
-      * We would prefer to go through the parentid keys just once from 
 
-      * highest id to lowest id but the btree ordering is by string
 
-      * rather than number. So we go through the parentid keys in btree
 
-      * order first of all to create an idlist of all the non-leaf nodes.
 
-      * Then we can use the idlist to iterate through parentid in the
 
-      * correct order.
 
-      */
 
-     LDAPDebug(LDAP_DEBUG_TRACE, "Creating ancestorid index\n", 0,0,0);
 
-     /* Get the non-leaf node IDs */
 
-     ret = ldbm_get_nonleaf_ids(be, txn, &nodes);
 
-     if (ret != 0) return ret;
 
-     /* Get the ancestorid index */
 
-     ainfo_get(be, LDBM_ANCESTORID_STR, &ai_aid);
 
-     /* Prevent any other use of the index */
 
-     ai_aid->ai_indexmask |= INDEX_OFFLINE;
 
-     /* Open the ancestorid index file */
 
-     ret = dblayer_get_index_file(be, ai_aid, &db_aid, DBOPEN_CREATE);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13050,ret);
 
-         goto out;
 
-     }
 
-     /* Maybe nothing to do */
 
-     if (nodes == NULL || nodes->b_nids == 0) {
 
-         LDAPDebug(LDAP_DEBUG_ANY, "Nothing to do to build ancestorid index\n",
 
-                   0, 0, 0);
 
-         goto out;
 
-     }
 
-     /* Create an ancestorid cache */
 
-     ht = id2idl_new_hash(nodes->b_nids);
 
-     /* Get the parentid index */
 
-     ainfo_get( be, LDBM_PARENTID_STR, &ai_pid );
 
-     /* Open the parentid index file */
 
-     ret = dblayer_get_index_file(be, ai_pid, &db_pid, DBOPEN_CREATE);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13060,ret);
 
-         goto out;
 
-     }
 
-     /* Initialize key DBT */
 
-     key.data = keybuf;
 
-     key.ulen = sizeof(keybuf);
 
-     key.flags = DB_DBT_USERMEM;
 
-     /* Iterate from highest to lowest ID */
 
-     nids = nodes->b_nids;
 
-     do {
 
-         nids--;
 
-         id = nodes->b_ids[nids];
 
-         /* Get immediate children from parentid index */
 
-         key.size = PR_snprintf(key.data, key.ulen, "%c%lu", 
 
-                                EQ_PREFIX, (u_long)id);
 
-         key.size++;             /* include the null terminator */
 
-         ret = NEW_IDL_NO_ALLID;
 
-         children = idl_fetch(be, db_pid, &key, txn, ai_pid, &ret);
 
-         if (ret != 0) {
 
-             ldbm_nasty(sourcefile,13070,ret);
 
-             break;
 
-         }
 
-         /* Insert into ancestorid for this node */
 
-         if (id2idl_hash_lookup(ht, &id, &ididl)) {
 
-             descendants = idl_union_allids(be, ai_aid, ididl->idl, children);
 
-             idl_free(&children);
 
-             if (id2idl_hash_remove(ht, &id) == 0) {
 
-                 LDAPDebug(LDAP_DEBUG_ANY, "ancestorid hash_remove failed\n", 0,0,0);
 
-             } else {
 
-                 id2idl_free(&ididl);
 
-             }
 
-         } else {
 
-             descendants = children;
 
-         }
 
-         ret = idl_store_block(be, db_aid, &key, descendants, txn, ai_aid);
 
-         if (ret != 0) break;
 
-         /* Get parentid for this entry */
 
-         ret = ldbm_parentid(be, txn, id, &parentid);
 
-         if (ret != 0) {
 
-             idl_free(&descendants);
 
-             break;
 
-         }
 
-         /* A suffix entry does not have a parent */
 
-         if (parentid == NOID) {
 
-             idl_free(&descendants);
 
-             continue;
 
-         }
 
-         /* Insert into ancestorid for this node's parent */
 
-         if (id2idl_hash_lookup(ht, &parentid, &ididl)) {
 
-             IDList *idl = idl_union_allids(be, ai_aid, ididl->idl, descendants);
 
-             idl_free(&descendants);
 
-             idl_free(&(ididl->idl));
 
-             ididl->idl = idl;
 
-         } else {
 
-             ididl = (id2idl*)slapi_ch_calloc(1,sizeof(id2idl));
 
-             ididl->keyid = parentid;
 
-             ididl->idl = descendants;
 
-             if (id2idl_hash_add(ht, &parentid, ididl, NULL) == 0) {
 
-                 LDAPDebug(LDAP_DEBUG_ANY, "ancestorid hash_add failed\n", 0,0,0);
 
-             }
 
-         }
 
-     } while (nids > 0);
 
-     if (ret != 0) {
 
-         goto out;
 
-     }
 
-     /* We're expecting the cache to be empty */
 
-     ret = check_cache(ht);
 
-  out:
 
-     if (ret == 0) {
 
-         LDAPDebug(LDAP_DEBUG_TRACE, "Created ancestorid index\n", 0,0,0);
 
-     } else {
 
-         LDAPDebug(LDAP_DEBUG_ANY, "Failed to create ancestorid index\n", 0,0,0);
 
-     }
 
-     /* Destroy the cache */
 
-     id2idl_hash_destroy(ht);
 
-     /* Free any leftover idlists */
 
-     idl_free(&nodes);
 
-     /* Release the parentid file */
 
-     if (db_pid != NULL) {
 
-         dblayer_release_index_file( be, ai_pid, db_pid );
 
-     }
 
-     /* Release the ancestorid file */
 
-     if (db_aid != NULL) {
 
-         dblayer_release_index_file( be, ai_aid, db_aid );
 
-     }
 
-     /* Enable the index */
 
-     if (ret == 0) {
 
-         ai_aid->ai_indexmask &= ~INDEX_OFFLINE;
 
-     }
 
-     return ret;
 
- }
 
- /*
 
-  * Create the ancestorid index.  This version expects to use
 
-  * idl_new_store_block() and should be used when idl_new != 0.
 
-  * It has lower overhead and can be faster than 
 
-  * ldbm_ancestorid_default_create_index(), particularly on
 
-  * large databases.  Cf. bug 469800.
 
-  */
 
- static int ldbm_ancestorid_new_idl_create_index(backend *be)
 
- {
 
-     int ret = 0;
 
-     DB *db_pid    = NULL;
 
-     DB *db_aid    = NULL;
 
-     DBT key  = {0};
 
-     DB_TXN *txn = NULL;
 
-     struct attrinfo *ai_pid = NULL;
 
-     struct attrinfo *ai_aid = NULL;
 
-     char keybuf[24];
 
-     IDList *nodes = NULL;
 
-     IDList *children = NULL;
 
-     NIDS nids;
 
-     ID id, parentid;
 
-     /*
 
-      * We need to iterate depth-first through the non-leaf nodes
 
-      * in the tree amassing an idlist of descendant ids for each node.
 
-      * We would prefer to go through the parentid keys just once from 
 
-      * highest id to lowest id but the btree ordering is by string
 
-      * rather than number. So we go through the parentid keys in btree
 
-      * order first of all to create an idlist of all the non-leaf nodes.
 
-      * Then we can use the idlist to iterate through parentid in the
 
-      * correct order.
 
-      */
 
-     LDAPDebug(LDAP_DEBUG_TRACE, "Creating ancestorid index\n", 0,0,0);
 
- 	/* Bail now if we did not get here honestly. */
 
- 	if (!idl_get_idl_new()) {
 
- 		LDAPDebug(LDAP_DEBUG_ANY, "Cannot create ancestorid index.  " 
 
- 			"New IDL version called but idl_new is false!\n", 0,0,0);
 
- 		return 1;
 
- 	}
 
-     /* Get the non-leaf node IDs */
 
-     ret = ldbm_get_nonleaf_ids(be, txn, &nodes);
 
-     if (ret != 0) return ret;
 
-     /* Get the ancestorid index */
 
-     ainfo_get(be, LDBM_ANCESTORID_STR, &ai_aid);
 
-     /* Prevent any other use of the index */
 
-     ai_aid->ai_indexmask |= INDEX_OFFLINE;
 
-     /* Open the ancestorid index file */
 
-     ret = dblayer_get_index_file(be, ai_aid, &db_aid, DBOPEN_CREATE);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13050,ret);
 
-         goto out;
 
-     }
 
-     /* Maybe nothing to do */
 
-     if (nodes == NULL || nodes->b_nids == 0) {
 
-         LDAPDebug(LDAP_DEBUG_ANY, "Nothing to do to build ancestorid index\n",
 
-                   0, 0, 0);
 
-         goto out;
 
-     }
 
-     /* Get the parentid index */
 
-     ainfo_get( be, LDBM_PARENTID_STR, &ai_pid );
 
-     /* Open the parentid index file */
 
-     ret = dblayer_get_index_file(be, ai_pid, &db_pid, DBOPEN_CREATE);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13060,ret);
 
-         goto out;
 
-     }
 
-     /* Initialize key DBT */
 
-     key.data = keybuf;
 
-     key.ulen = sizeof(keybuf);
 
-     key.flags = DB_DBT_USERMEM;
 
-     /* Iterate from highest to lowest ID */
 
-     nids = nodes->b_nids;
 
-     do {
 
-         nids--;
 
-         id = nodes->b_ids[nids];
 
-         /* Get immediate children from parentid index */
 
-         key.size = PR_snprintf(key.data, key.ulen, "%c%lu", 
 
-                                EQ_PREFIX, (u_long)id);
 
-         key.size++;             /* include the null terminator */
 
-         ret = NEW_IDL_NO_ALLID;
 
-         children = idl_fetch(be, db_pid, &key, txn, ai_pid, &ret);
 
-         if (ret != 0) {
 
-             ldbm_nasty(sourcefile,13070,ret);
 
-             break;
 
-         }
 
- 		/* Instead of maintaining a full accounting of IDs in a hashtable
 
- 		 * as is done with ldbm_ancestorid_default_create_index(), perform
 
- 		 * incremental updates straight to the DB with idl_new_store_block()
 
- 		 * (used by idl_store_block() when idl_get_idl_new() is true).  This 
 
- 		 * can be a significant performance improvement with large databases,
 
- 		 * where  the overhead of maintaining and copying the lists is very
 
- 		 * expensive, particularly when the allids threshold is not being
 
- 		 * used to provide any cut off.  Cf. bug 469800.
 
- 		 * TEL 20081029 */
 
-         /* Insert into ancestorid for this node */
 
-         ret = idl_store_block(be, db_aid, &key, children, txn, ai_aid);
 
-         if (ret != 0) {
 
-             idl_free(&children);
 
-             break;
 
-         }
 
-         /* Get parentid(s) for this entry */
 
-         while (1) {
 
-             ret = ldbm_parentid(be, txn, id, &parentid);
 
-             if (ret != 0) {
 
-                 slapi_log_error(SLAPI_LOG_FATAL, sourcefile,
 
-                                 "Error: ldbm_parentid on node index [" ID_FMT "] of [" ID_FMT "]\n",
 
-                                 nids, nodes->b_nids);
 
-                 idl_free(&children);
 
-                 goto out;
 
-             }
 
-     
 
-             /* A suffix entry does not have a parent */
 
-             if (parentid == NOID) {
 
-                 idl_free(&children);
 
-                 break;
 
-             }
 
-     
 
-             /* Reset the key to the parent id */
 
-             key.size = PR_snprintf(key.data, key.ulen, "%c%lu", 
 
-                                    EQ_PREFIX, (u_long)parentid);
 
-             key.size++;
 
-     
 
-             /* Insert into ancestorid for this node's parent */
 
-             ret = idl_store_block(be, db_aid, &key, children, txn, ai_aid);
 
-             if (ret != 0) {
 
-                 idl_free(&children);
 
-                 goto out;
 
-             }
 
-             id = parentid;
 
-         }
 
-     } while (nids > 0);
 
-     if (ret != 0) {
 
-         goto out;
 
-     }
 
-  out:
 
-     if (ret == 0) {
 
-         LDAPDebug(LDAP_DEBUG_TRACE, "Created ancestorid index\n", 0,0,0);
 
-     } else {
 
-         LDAPDebug(LDAP_DEBUG_ANY, "Failed to create ancestorid index\n", 0,0,0);
 
-     }
 
-     /* Free any leftover idlists */
 
-     idl_free(&nodes);
 
-     /* Release the parentid file */
 
-     if (db_pid != NULL) {
 
-         dblayer_release_index_file( be, ai_pid, db_pid );
 
-     }
 
-     /* Release the ancestorid file */
 
-     if (db_aid != NULL) {
 
-         dblayer_release_index_file( be, ai_aid, db_aid );
 
-     }
 
-     /* Enable the index */
 
-     if (ret == 0) {
 
-         ai_aid->ai_indexmask &= ~INDEX_OFFLINE;
 
-     }
 
-     return ret;
 
- }
 
- /*
 
-  * Get parentid of an id by reading the operational attr from id2entry.
 
-  */
 
- static int ldbm_parentid(backend *be, DB_TXN *txn, ID id, ID *ppid)
 
- {
 
-     int ret = 0;
 
-     DB *db = NULL;
 
-     DBT	key = {0};
 
-     DBT data = {0};
 
-     ID stored_id;
 
-     char *p;
 
-     /* Open the id2entry file */
 
-     ret = dblayer_get_id2entry(be, &db);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13100,ret);
 
-         goto out;
 
-     }
 
-     /* Initialize key and data DBTs */
 
-     id_internal_to_stored(id, (char *)&stored_id);
 
-     key.data = (char *)&stored_id;
 
-     key.size = sizeof(stored_id);
 
-     key.flags = DB_DBT_USERMEM;
 
-     data.flags = DB_DBT_MALLOC;
 
-     /* Read id2entry */
 
-     ret = db->get(db, txn, &key, &data, 0);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13110,ret);
 
-         slapi_log_error(SLAPI_LOG_FATAL, sourcefile,
 
-                         "Error: unable to find entry id [" ID_FMT "] (original [" ID_FMT "])"
 
-                         " in id2entry\n", stored_id, id);
 
-         goto out;
 
-     }
 
-     /* Extract the parentid value */
 
- #define PARENTID_STR "\nparentid:"
 
-     p = strstr(data.data, PARENTID_STR);
 
-     if (p == NULL) {
 
-         *ppid = NOID;
 
-         goto out;
 
-     }
 
-     *ppid = strtoul(p + strlen(PARENTID_STR), NULL, 10);
 
-  out:
 
-     /* Free the entry value */
 
-     slapi_ch_free(&(data.data));
 
-     /* Release the id2entry file */
 
-     if (db != NULL) {
 
-         dblayer_release_id2entry(be, db);
 
-     }
 
-     return ret;
 
- }
 
- static void id2idl_free(id2idl **ididl)
 
- {
 
-     idl_free(&((*ididl)->idl));
 
-     slapi_ch_free((void**)ididl);
 
- }
 
- static int id2idl_same_key(const void *ididl, const void *k)
 
- {
 
-     return (((id2idl *)ididl)->keyid == *(ID *)k);
 
- }
 
- static int check_cache(id2idl_hash *ht)
 
- {
 
-     id2idl *e;
 
-     u_long i, found = 0;
 
-     int ret = 0;
 
-     if (ht == NULL) return 0;
 
-     for (i = 0; i < ht->size; i++) {
 
- 	e = (id2idl *)ht->slot[i];
 
-         while (e) {
 
-             found++;
 
-             e = e->next;
 
-         }
 
-     }
 
-     if (found > 0) {
 
-         LDAPDebug(LDAP_DEBUG_ANY, "ERROR: parentid index is not complete (%lu extra keys in ancestorid cache)\n", found,0,0);
 
-         ret = -1;
 
-     }
 
-     return ret;
 
- }
 
- static void id2idl_hash_destroy(id2idl_hash *ht)
 
- {
 
-     u_long i;
 
-     id2idl *e, *next;
 
-     if (ht == NULL) return;
 
-     for (i = 0; i < ht->size; i++) {
 
- 	e = (id2idl *)ht->slot[i];
 
-         while (e) {
 
-             next = e->next;
 
-             id2idl_free(&e);
 
-             e = next;
 
-         }
 
-     }
 
-     slapi_ch_free((void **)&ht);
 
- }
 
- /*
 
-  * idl_union_allids - return a union b
 
-  * takes attr index allids setting into account
 
-  */
 
- static IDList *idl_union_allids(backend *be, struct attrinfo *ai, IDList *a, IDList *b)
 
- {
 
-     if (!idl_get_idl_new()) {
 
-         if (a != NULL && b != NULL) {
 
-             if (ALLIDS( a ) || ALLIDS( b ) || 
 
-                 (IDL_NIDS(a) + IDL_NIDS(b) > idl_get_allidslimit(ai, 0))) {
 
-                 return( idl_allids( be ) );
 
-             }
 
-         }
 
-     }
 
-     return idl_union(be, a, b);
 
- }
 
- static int ancestorid_addordel(
 
-     backend *be, 
 
-     DB* db, 
 
-     ID node_id, 
 
-     ID id, 
 
-     DB_TXN *txn, 
 
-     struct attrinfo *ai,
 
-     int flags,
 
-     int *allids
 
- )
 
- {
 
-     DBT key = {0};
 
-     char keybuf[24];
 
-     int ret = 0;
 
-     /* Initialize key DBT */
 
-     key.data = keybuf;
 
-     key.ulen = sizeof(keybuf);
 
-     key.flags = DB_DBT_USERMEM;
 
-     key.size = PR_snprintf(key.data, key.ulen, "%c%lu", 
 
-                            EQ_PREFIX, (u_long)node_id);
 
-     key.size++;             /* include the null terminator */
 
-     if (flags & BE_INDEX_ADD) {
 
- #if 1
 
-         LDAPDebug(LDAP_DEBUG_TRACE, "insert ancestorid %lu:%lu\n", 
 
-                   (u_long)node_id, (u_long)id, 0);
 
- #endif
 
-         ret = idl_insert_key(be, db, &key, id, txn, ai, allids);
 
-     } else {
 
- #if 1
 
-         LDAPDebug(LDAP_DEBUG_TRACE, "delete ancestorid %lu:%lu\n", 
 
-                   (u_long)node_id, (u_long)id, 0);
 
- #endif
 
-         ret = idl_delete_key(be, db, &key, id, txn, ai);
 
-     }
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13120,ret);
 
-     }
 
-     return ret;
 
- }
 
- /* 
 
-  * Update ancestorid index inserting or deleting depending on flags.
 
-  * The entry ids to be indexed are given by id (a base object)
 
-  * and optionally subtree_idl (descendants of the base object).
 
-  * The ancestorid keys to be updated are derived from nodes
 
-  * in the tree from low up to high. Whether the low and high nodes
 
-  * themselves are updated is given by include_low and include_high.
 
-  */
 
- static int ldbm_ancestorid_index_update(
 
-     backend		*be,
 
-     const Slapi_DN	*low,
 
-     const Slapi_DN	*high,
 
-     int			include_low,
 
-     int			include_high,
 
-     ID			id,
 
-     IDList		*subtree_idl,
 
-     int			flags,  /* BE_INDEX_ADD, BE_INDEX_DEL */
 
-     back_txn		*txn
 
- )
 
- {
 
-     DB *db = NULL;
 
-     int allids = IDL_INSERT_NORMAL;
 
-     Slapi_DN sdn;
 
-     Slapi_DN nextsdn;
 
-     struct attrinfo *ai = NULL;
 
-     ID node_id, sub_id;
 
-     idl_iterator iter;
 
-     int err = 0, ret = 0;
 
-     DB_TXN *db_txn = txn != NULL ? txn->back_txn_txn : NULL;
 
-     slapi_sdn_init(&sdn);
 
-     slapi_sdn_init(&nextsdn);
 
-     /* Open the ancestorid index */
 
-     ainfo_get(be, LDBM_ANCESTORID_STR, &ai);
 
-     ret = dblayer_get_index_file(be, ai, &db, DBOPEN_CREATE);
 
-     if (ret != 0) {
 
-         ldbm_nasty(sourcefile,13130,ret);
 
-         goto out;
 
-     }
 
-     slapi_sdn_copy(low, &sdn);
 
-     if (include_low == 0) {
 
-         if (slapi_sdn_compare(&sdn, high) == 0) {
 
-             goto out;
 
-         }
 
-         /* Get the next highest DN */
 
-         slapi_sdn_get_parent(&sdn, &nextsdn);
 
-         slapi_sdn_copy(&nextsdn, &sdn);
 
-     }
 
-     /* Iterate up through the tree */
 
-     do {
 
-         if (slapi_sdn_isempty(&sdn)) {
 
-             break;
 
-         }
 
-         /* Have we reached the high node? */
 
-         if (include_high == 0 && slapi_sdn_compare(&sdn, high) == 0) {
 
-             break;
 
-         }
 
-         /* Get the id for that DN */
 
-         if (entryrdn_get_switch()) { /* subtree-rename: on */
 
-             node_id = 0;
 
-             err = entryrdn_index_read(be, &sdn, &node_id, txn);
 
-             if (err) {
 
-                 if (DB_NOTFOUND != err) {
 
-                     ldbm_nasty(sourcefile,13141,err);
 
-                     LDAPDebug1Arg(LDAP_DEBUG_ANY, "entryrdn_index_read(%s)\n", slapi_sdn_get_dn(&sdn));
 
-                     ret = err;
 
-                 }
 
-                 break;
 
-             }
 
-         } else {
 
-             IDList *idl = NULL;
 
-             struct berval ndnv;
 
-             ndnv.bv_val = (void*)slapi_sdn_get_ndn(&sdn);
 
-             ndnv.bv_len = slapi_sdn_get_ndn_len(&sdn);
 
-             err = 0;
 
-             idl = index_read(be, LDBM_ENTRYDN_STR, indextype_EQUALITY, &ndnv, txn, &err);
 
-             if (idl == NULL) {
 
-                 if (err != 0 && err != DB_NOTFOUND) {
 
-                     ldbm_nasty(sourcefile,13140,err);
 
-                     ret = err;
 
-                 }
 
-                 break;
 
-             }
 
-             node_id = idl_firstid(idl);
 
-             idl_free(&idl);
 
-         }
 
-         /* Update ancestorid for the base entry */
 
-         ret = ancestorid_addordel(be, db, node_id, id, db_txn, ai, flags, &allids);
 
-         if (ret != 0) break;
 
-         /* 
 
-          * If this node was already allids then all higher nodes must already 
 
-          * be at allids since the higher nodes must have a greater number
 
-          * of descendants. Therefore no point continuing.
 
-          */
 
-         if (allids == IDL_INSERT_ALLIDS) break;
 
-         /* Update ancestorid for any subtree entries */
 
-         if (subtree_idl != NULL && ((flags & BE_INDEX_ADD) || (!ALLIDS(subtree_idl)))) {
 
-             iter = idl_iterator_init(subtree_idl);
 
-             while ((sub_id = idl_iterator_dereference_increment(&iter, subtree_idl)) != NOID) {
 
-                 ret = ancestorid_addordel(be, db, node_id, sub_id, db_txn, ai, flags, &allids);
 
-                 if (ret != 0) break;
 
-             }
 
-             if (ret != 0) break;
 
-         }
 
-         /* Have we reached the high node? */
 
-         if (slapi_sdn_compare(&sdn, high) == 0) {
 
-             break;
 
-         }
 
-         /* Get the next highest DN */
 
-         slapi_sdn_get_parent(&sdn, &nextsdn);
 
-         slapi_sdn_copy(&nextsdn, &sdn);
 
-     } while (ret == 0);
 
- out:
 
-     slapi_sdn_done(&sdn);
 
-     slapi_sdn_done(&nextsdn);
 
-     /* Release the ancestorid file */
 
-     if (db != NULL) {
 
-         dblayer_release_index_file(be, ai, db);
 
-     }
 
-     return ret;
 
- }
 
- /*
 
-  * Update the ancestorid index for a single entry.
 
-  * This function depends on the integrity of the entrydn index.
 
-  */
 
- int ldbm_ancestorid_index_entry(
 
-     backend		*be,
 
-     struct backentry	*e,
 
-     int			flags,  /* BE_INDEX_ADD, BE_INDEX_DEL */
 
-     back_txn		*txn
 
- )
 
- {
 
-     int ret = 0;
 
-     ret = ldbm_ancestorid_index_update(be,
 
-                                        slapi_entry_get_sdn_const(e->ep_entry), 
 
-                                        slapi_be_getsuffix(be, 0), 
 
-                                        0, 1, e->ep_id, NULL, flags, txn);
 
-     return ret;
 
- }
 
- /*
 
-  * Returns <0, 0, >0 according to whether right is a suffix of left,
 
-  * neither is a suffix of the other, or left is a suffix of right.
 
-  * If common is non-null then the common suffix of left and right
 
-  * is returned in *common.
 
-  */
 
- static int 
 
- _sdn_suffix_cmp(
 
-     const Slapi_DN *left, 
 
-     const Slapi_DN *right, 
 
-     Slapi_DN *common
 
- )
 
- {
 
-     char **rdns1, **rdns2;
 
-     int count1, count2, i, ret = 0;
 
-     size_t len = 0;
 
-     char *p, *ndnstr;
 
-     rdns1 = slapi_ldap_explode_dn(slapi_sdn_get_ndn(left), 0);
 
-     rdns2 = slapi_ldap_explode_dn(slapi_sdn_get_ndn(right), 0);
 
-     if (NULL == rdns1) {
 
-         if (NULL == rdns2) {
 
-             ret = 0;
 
-         } else {
 
-             ret = 1;
 
-         }
 
-         goto out;
 
-     } else {
 
-         if (NULL == rdns2) {
 
-             ret = -1;
 
-             goto out;
 
-         }
 
-     }
 
-     for(count1 = 0; rdns1[count1]!=NULL; count1++) ;
 
-     count1--;
 
-     for(count2 = 0; rdns2[count2]!=NULL; count2++) ;
 
-     count2--;
 
-     while (count1 >= 0 && count2 >= 0) {
 
-         if (strcmp(rdns1[count1], rdns2[count2]) != 0) break;
 
-         count1--;
 
-         count2--;
 
-     }
 
-     count1++;
 
-     count2++;
 
-     if (count1 == 0 && count2 == 0) {
 
-         /* equal */
 
-         ret = 0;
 
-     } else if (count1 == 0) {
 
-         /* left is suffix of right */
 
-         ret = 1;
 
-     } else if (count2 == 0) {
 
-         /* right is suffix of left */
 
-         ret = -1;
 
-     } else {
 
-         /* common prefix (possibly root), not left nor right */
 
-         ret = 0;
 
-     }
 
-     /* if caller does not want the common prefix then we're done */
 
-     if (common == NULL) goto out;
 
-     /* figure out how much space we need */
 
-     for (i = count1; rdns1[i] != NULL; i++) {
 
-         len += strlen(rdns1[i]) + 1;
 
-     }
 
-     /* write the string */
 
-     p = ndnstr = slapi_ch_calloc(len+1,sizeof(char));
 
-     for (i = count1; rdns1[i] != NULL; i++) {
 
-         sprintf(p, "%s%s", (p != ndnstr) ? "," : "", rdns1[i]);
 
-         p += strlen(p);
 
-     }
 
-     /* return the DN */
 
-     slapi_sdn_set_dn_passin(common, ndnstr);
 
-     LDAPDebug(LDAP_DEBUG_TRACE, "common suffix <%s>\n",
 
-               slapi_sdn_get_dn(common), 0, 0);
 
- out:
 
-     slapi_ldap_value_free(rdns1);
 
-     slapi_ldap_value_free(rdns2);
 
-     LDAPDebug(LDAP_DEBUG_TRACE, "_sdn_suffix_cmp(<%s>, <%s>) => %d\n",
 
-               slapi_sdn_get_dn(left), slapi_sdn_get_dn(right), ret);
 
-     return ret;
 
- }
 
- int ldbm_ancestorid_move_subtree(
 
-     backend		*be,
 
-     const Slapi_DN	*olddn,
 
-     const Slapi_DN	*newdn,
 
-     ID			id,
 
-     IDList		*subtree_idl,
 
-     back_txn		*txn
 
- )
 
- {
 
-     int ret = 0;
 
-     Slapi_DN commonsdn;
 
-     slapi_sdn_init(&commonsdn);
 
-     /* Determine the common ancestor */
 
-     (void)_sdn_suffix_cmp(olddn, newdn, &commonsdn);
 
-     /* Delete from old ancestors */
 
-     ret = ldbm_ancestorid_index_update(be, 
 
-                                        olddn,
 
-                                        &commonsdn,
 
-                                        0,
 
-                                        0,
 
-                                        id,
 
-                                        subtree_idl,
 
-                                        BE_INDEX_DEL,
 
-                                        txn);
 
-     if (ret != 0) goto out;
 
-     /* Add to new ancestors */
 
-     ret = ldbm_ancestorid_index_update(be, 
 
-                                        newdn,
 
-                                        &commonsdn,
 
-                                        0,
 
-                                        0,
 
-                                        id,
 
-                                        subtree_idl,
 
-                                        BE_INDEX_ADD,
 
-                                        txn);
 
-  out:
 
-     slapi_sdn_done(&commonsdn);
 
-     return ret;
 
- }
 
- int ldbm_ancestorid_read_ext(
 
-     backend		*be,
 
-     back_txn		*txn,
 
-     ID			id,
 
-     IDList		**idl,
 
-     int         allidslimit
 
- )
 
- {
 
-     int ret = 0;
 
-     struct berval bv;
 
-     char keybuf[24];
 
-     bv.bv_val = keybuf;
 
-     bv.bv_len = PR_snprintf(keybuf, sizeof(keybuf), "%lu", (u_long)id);
 
-     *idl = index_read_ext_allids(NULL, be, LDBM_ANCESTORID_STR, indextype_EQUALITY, &bv, txn, &ret, NULL, allidslimit);
 
-     return ret;
 
- }
 
- int ldbm_ancestorid_read(
 
-     backend		*be,
 
-     back_txn		*txn,
 
-     ID			id,
 
-     IDList		**idl
 
- )
 
- {
 
-     return ldbm_ancestorid_read_ext(be, txn, id, idl, 0);
 
- }
 
 
  |