1/* $NetBSD: dn2id.c,v 1.1.1.4 2010/12/12 15:22:54 adam Exp $ */ 2 3/* dn2id.c - routines to deal with the dn2id index */ 4/* OpenLDAP: pkg/ldap/servers/slapd/back-bdb/dn2id.c,v 1.137.2.23 2010/06/23 15:57:26 quanah Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2010 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19#include "portable.h" 20 21#include <stdio.h> 22#include <ac/string.h> 23 24#include "back-bdb.h" 25#include "idl.h" 26#include "lutil.h" 27 28#define bdb_dn2id_lock BDB_SYMBOL(dn2id_lock) 29 30static int 31bdb_dn2id_lock( struct bdb_info *bdb, struct berval *dn, 32 int rw, DB_TXN *txn, DB_LOCK *lock ) 33{ 34 int rc; 35 DBT lockobj; 36 int db_rw; 37 38 if (!txn) 39 return 0; 40 41 if (rw) 42 db_rw = DB_LOCK_WRITE; 43 else 44 db_rw = DB_LOCK_READ; 45 46 lockobj.data = dn->bv_val; 47 lockobj.size = dn->bv_len; 48 49 rc = LOCK_GET(bdb->bi_dbenv, TXN_ID(txn), DB_LOCK_NOWAIT, 50 &lockobj, db_rw, lock); 51 return rc; 52} 53 54#ifndef BDB_HIER 55int 56bdb_dn2id_add( 57 Operation *op, 58 DB_TXN *txn, 59 EntryInfo *eip, 60 Entry *e ) 61{ 62 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 63 DB *db = bdb->bi_dn2id->bdi_db; 64 int rc; 65 DBT key, data; 66 ID nid; 67 char *buf; 68 struct berval ptr, pdn; 69 70 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add 0x%lx: \"%s\"\n", 71 e->e_id, e->e_ndn, 0 ); 72 assert( e->e_id != NOID ); 73 74 DBTzero( &key ); 75 key.size = e->e_nname.bv_len + 2; 76 key.ulen = key.size; 77 key.flags = DB_DBT_USERMEM; 78 buf = op->o_tmpalloc( key.size, op->o_tmpmemctx ); 79 key.data = buf; 80 buf[0] = DN_BASE_PREFIX; 81 ptr.bv_val = buf + 1; 82 ptr.bv_len = e->e_nname.bv_len; 83 AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); 84 ptr.bv_val[ptr.bv_len] = '\0'; 85 86 DBTzero( &data ); 87 data.data = &nid; 88 data.size = sizeof( nid ); 89 BDB_ID2DISK( e->e_id, &nid ); 90 91 /* store it -- don't override */ 92 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); 93 if( rc != 0 ) { 94 char buf[ SLAP_TEXT_BUFLEN ]; 95 snprintf( buf, sizeof( buf ), "%s => bdb_dn2id_add dn=\"%s\" ID=0x%lx", 96 op->o_log_prefix, e->e_name.bv_val, e->e_id ); 97 Debug( LDAP_DEBUG_ANY, "%s: put failed: %s %d\n", 98 buf, db_strerror(rc), rc ); 99 goto done; 100 } 101 102#ifndef BDB_MULTIPLE_SUFFIXES 103 if( !be_issuffix( op->o_bd, &ptr )) 104#endif 105 { 106 buf[0] = DN_SUBTREE_PREFIX; 107 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); 108 if( rc != 0 ) { 109 Debug( LDAP_DEBUG_ANY, 110 "=> bdb_dn2id_add 0x%lx: subtree (%s) put failed: %d\n", 111 e->e_id, ptr.bv_val, rc ); 112 goto done; 113 } 114 115#ifdef BDB_MULTIPLE_SUFFIXES 116 if( !be_issuffix( op->o_bd, &ptr )) 117#endif 118 { 119 dnParent( &ptr, &pdn ); 120 121 key.size = pdn.bv_len + 2; 122 key.ulen = key.size; 123 pdn.bv_val[-1] = DN_ONE_PREFIX; 124 key.data = pdn.bv_val-1; 125 ptr = pdn; 126 127 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id ); 128 129 if( rc != 0 ) { 130 Debug( LDAP_DEBUG_ANY, 131 "=> bdb_dn2id_add 0x%lx: parent (%s) insert failed: %d\n", 132 e->e_id, ptr.bv_val, rc ); 133 goto done; 134 } 135 } 136 137#ifndef BDB_MULTIPLE_SUFFIXES 138 while( !be_issuffix( op->o_bd, &ptr )) 139#else 140 for (;;) 141#endif 142 { 143 ptr.bv_val[-1] = DN_SUBTREE_PREFIX; 144 145 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id ); 146 147 if( rc != 0 ) { 148 Debug( LDAP_DEBUG_ANY, 149 "=> bdb_dn2id_add 0x%lx: subtree (%s) insert failed: %d\n", 150 e->e_id, ptr.bv_val, rc ); 151 break; 152 } 153#ifdef BDB_MULTIPLE_SUFFIXES 154 if( be_issuffix( op->o_bd, &ptr )) break; 155#endif 156 dnParent( &ptr, &pdn ); 157 158 key.size = pdn.bv_len + 2; 159 key.ulen = key.size; 160 key.data = pdn.bv_val - 1; 161 ptr = pdn; 162 } 163 } 164 165done: 166 op->o_tmpfree( buf, op->o_tmpmemctx ); 167 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 ); 168 return rc; 169} 170 171int 172bdb_dn2id_delete( 173 Operation *op, 174 DB_TXN *txn, 175 EntryInfo *eip, 176 Entry *e ) 177{ 178 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 179 DB *db = bdb->bi_dn2id->bdi_db; 180 char *buf; 181 DBT key; 182 DB_LOCK lock; 183 struct berval pdn, ptr; 184 int rc; 185 186 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete 0x%lx: \"%s\"\n", 187 e->e_id, e->e_ndn, 0 ); 188 189 DBTzero( &key ); 190 key.size = e->e_nname.bv_len + 2; 191 buf = op->o_tmpalloc( key.size, op->o_tmpmemctx ); 192 key.data = buf; 193 key.flags = DB_DBT_USERMEM; 194 buf[0] = DN_BASE_PREFIX; 195 ptr.bv_val = buf+1; 196 ptr.bv_len = e->e_nname.bv_len; 197 AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); 198 ptr.bv_val[ptr.bv_len] = '\0'; 199 200 /* We hold this lock until the TXN completes */ 201 rc = bdb_dn2id_lock( bdb, &e->e_nname, 1, txn, &lock ); 202 if ( rc ) goto done; 203 204 /* delete it */ 205 rc = db->del( db, txn, &key, 0 ); 206 if( rc != 0 ) { 207 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: delete failed: %s %d\n", 208 e->e_id, db_strerror(rc), rc ); 209 goto done; 210 } 211 212#ifndef BDB_MULTIPLE_SUFFIXES 213 if( !be_issuffix( op->o_bd, &ptr )) 214#endif 215 { 216 buf[0] = DN_SUBTREE_PREFIX; 217 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id ); 218 if( rc != 0 ) { 219 Debug( LDAP_DEBUG_ANY, 220 "=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n", 221 e->e_id, ptr.bv_val, rc ); 222 goto done; 223 } 224 225#ifdef BDB_MULTIPLE_SUFFIXES 226 if( !be_issuffix( op->o_bd, &ptr )) 227#endif 228 { 229 dnParent( &ptr, &pdn ); 230 231 key.size = pdn.bv_len + 2; 232 key.ulen = key.size; 233 pdn.bv_val[-1] = DN_ONE_PREFIX; 234 key.data = pdn.bv_val - 1; 235 ptr = pdn; 236 237 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id ); 238 239 if( rc != 0 ) { 240 Debug( LDAP_DEBUG_ANY, 241 "=> bdb_dn2id_delete 0x%lx: parent (%s) delete failed: %d\n", 242 e->e_id, ptr.bv_val, rc ); 243 goto done; 244 } 245 } 246 247#ifndef BDB_MULTIPLE_SUFFIXES 248 while( !be_issuffix( op->o_bd, &ptr )) 249#else 250 for (;;) 251#endif 252 { 253 ptr.bv_val[-1] = DN_SUBTREE_PREFIX; 254 255 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id ); 256 if( rc != 0 ) { 257 Debug( LDAP_DEBUG_ANY, 258 "=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n", 259 e->e_id, ptr.bv_val, rc ); 260 goto done; 261 } 262#ifdef BDB_MULTIPLE_SUFFIXES 263 if( be_issuffix( op->o_bd, &ptr )) break; 264#endif 265 dnParent( &ptr, &pdn ); 266 267 key.size = pdn.bv_len + 2; 268 key.ulen = key.size; 269 key.data = pdn.bv_val - 1; 270 ptr = pdn; 271 } 272 } 273 274done: 275 op->o_tmpfree( buf, op->o_tmpmemctx ); 276 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 ); 277 return rc; 278} 279 280int 281bdb_dn2id( 282 Operation *op, 283 struct berval *dn, 284 EntryInfo *ei, 285 DB_TXN *txn, 286 DB_LOCK *lock ) 287{ 288 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 289 DB *db = bdb->bi_dn2id->bdi_db; 290 DBC *cursor; 291 int rc; 292 DBT key, data; 293 ID nid; 294 295 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id(\"%s\")\n", dn->bv_val, 0, 0 ); 296 297 DBTzero( &key ); 298 key.size = dn->bv_len + 2; 299 key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx ); 300 ((char *)key.data)[0] = DN_BASE_PREFIX; 301 AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 ); 302 303 /* store the ID */ 304 DBTzero( &data ); 305 data.data = &nid; 306 data.ulen = sizeof(ID); 307 data.flags = DB_DBT_USERMEM; 308 309 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); 310 if ( rc ) goto func_leave; 311 312 rc = bdb_dn2id_lock( bdb, dn, 0, txn, lock ); 313 if ( rc ) goto nolock; 314 315 /* fetch it */ 316 rc = cursor->c_get( cursor, &key, &data, DB_SET ); 317 318nolock: 319 cursor->c_close( cursor ); 320func_leave: 321 322 if( rc != 0 ) { 323 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n", 324 db_strerror( rc ), rc, 0 ); 325 } else { 326 BDB_DISK2ID( &nid, &ei->bei_id ); 327 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%lx\n", 328 ei->bei_id, 0, 0 ); 329 } 330 op->o_tmpfree( key.data, op->o_tmpmemctx ); 331 return rc; 332} 333 334int 335bdb_dn2id_children( 336 Operation *op, 337 DB_TXN *txn, 338 Entry *e ) 339{ 340 DBT key, data; 341 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 342 DB *db = bdb->bi_dn2id->bdi_db; 343 ID id; 344 int rc; 345 346 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children(\"%s\")\n", 347 e->e_nname.bv_val, 0, 0 ); 348 DBTzero( &key ); 349 key.size = e->e_nname.bv_len + 2; 350 key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx ); 351 ((char *)key.data)[0] = DN_ONE_PREFIX; 352 AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 ); 353 354 if ( bdb->bi_idl_cache_size ) { 355 rc = bdb_idl_cache_get( bdb, db, &key, NULL ); 356 if ( rc != LDAP_NO_SUCH_OBJECT ) { 357 op->o_tmpfree( key.data, op->o_tmpmemctx ); 358 return rc; 359 } 360 } 361 /* we actually could do a empty get... */ 362 DBTzero( &data ); 363 data.data = &id; 364 data.ulen = sizeof(id); 365 data.flags = DB_DBT_USERMEM; 366 data.doff = 0; 367 data.dlen = sizeof(id); 368 369 rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags ); 370 op->o_tmpfree( key.data, op->o_tmpmemctx ); 371 372 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children(\"%s\"): %s (%d)\n", 373 e->e_nname.bv_val, 374 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " : 375 db_strerror(rc) ), rc ); 376 377 return rc; 378} 379 380int 381bdb_dn2idl( 382 Operation *op, 383 DB_TXN *txn, 384 struct berval *ndn, 385 EntryInfo *ei, 386 ID *ids, 387 ID *stack ) 388{ 389 int rc; 390 DBT key; 391 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 392 DB *db = bdb->bi_dn2id->bdi_db; 393 int prefix = ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) 394 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX; 395 396 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl(\"%s\")\n", 397 ndn->bv_val, 0, 0 ); 398 399#ifndef BDB_MULTIPLE_SUFFIXES 400 if ( prefix == DN_SUBTREE_PREFIX 401 && ( ei->bei_id == 0 || 402 ( ei->bei_parent->bei_id == 0 && op->o_bd->be_suffix[0].bv_len ))) { 403 BDB_IDL_ALL(bdb, ids); 404 return 0; 405 } 406#endif 407 408 DBTzero( &key ); 409 key.size = ndn->bv_len + 2; 410 key.ulen = key.size; 411 key.flags = DB_DBT_USERMEM; 412 key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx ); 413 ((char *)key.data)[0] = prefix; 414 AC_MEMCPY( &((char *)key.data)[1], ndn->bv_val, key.size - 1 ); 415 416 BDB_IDL_ZERO( ids ); 417 rc = bdb_idl_fetch_key( op->o_bd, db, txn, &key, ids, NULL, 0 ); 418 419 if( rc != 0 ) { 420 Debug( LDAP_DEBUG_TRACE, 421 "<= bdb_dn2idl: get failed: %s (%d)\n", 422 db_strerror( rc ), rc, 0 ); 423 424 } else { 425 Debug( LDAP_DEBUG_TRACE, 426 "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n", 427 (long) ids[0], 428 (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) ); 429 } 430 431 op->o_tmpfree( key.data, op->o_tmpmemctx ); 432 return rc; 433} 434 435#else /* BDB_HIER */ 436/* Management routines for a hierarchically structured database. 437 * 438 * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each 439 * entry in this database is a struct diskNode, keyed by entryID and with 440 * the data containing the RDN and entryID of the node's children. We use 441 * a B-Tree with sorted duplicates to store all the children of a node under 442 * the same key. Also, the first item under the key contains the entry's own 443 * rdn and the ID of the node's parent, to allow bottom-up tree traversal as 444 * well as top-down. To keep this info first in the list, the high bit of all 445 * subsequent nrdnlen's is always set. This means we can only accomodate 446 * RDNs up to length 32767, but that's fine since full DNs are already 447 * restricted to 8192. 448 * 449 * The diskNode is a variable length structure. This definition is not 450 * directly usable for in-memory manipulation. 451 */ 452typedef struct diskNode { 453 unsigned char nrdnlen[2]; 454 char nrdn[1]; 455 char rdn[1]; /* variable placement */ 456 unsigned char entryID[sizeof(ID)]; /* variable placement */ 457} diskNode; 458 459/* Sort function for the sorted duplicate data items of a dn2id key. 460 * Sorts based on normalized RDN, in length order. 461 */ 462int 463hdb_dup_compare( 464 DB *db, 465 const DBT *usrkey, 466 const DBT *curkey 467) 468{ 469 diskNode *un, *cn; 470 int rc; 471 472 un = (diskNode *)usrkey->data; 473 cn = (diskNode *)curkey->data; 474 475 /* data is not aligned, cannot compare directly */ 476 rc = un->nrdnlen[0] - cn->nrdnlen[0]; 477 if ( rc ) return rc; 478 rc = un->nrdnlen[1] - cn->nrdnlen[1]; 479 if ( rc ) return rc; 480 481 return strcmp( un->nrdn, cn->nrdn ); 482} 483 484/* This function constructs a full DN for a given entry. 485 */ 486int hdb_fix_dn( 487 Entry *e, 488 int checkit ) 489{ 490 EntryInfo *ei; 491 int rlen = 0, nrlen = 0; 492 char *ptr, *nptr; 493 int max = 0; 494 495 if ( !e->e_id ) 496 return 0; 497 498 /* count length of all DN components */ 499 for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) { 500 rlen += ei->bei_rdn.bv_len + 1; 501 nrlen += ei->bei_nrdn.bv_len + 1; 502 if (ei->bei_modrdns > max) max = ei->bei_modrdns; 503 } 504 505 /* See if the entry DN was invalidated by a subtree rename */ 506 if ( checkit ) { 507 if ( BEI(e)->bei_modrdns >= max ) { 508 return 0; 509 } 510 /* We found a mismatch, tell the caller to lock it */ 511 if ( checkit == 1 ) { 512 return 1; 513 } 514 /* checkit == 2. do the fix. */ 515 free( e->e_name.bv_val ); 516 free( e->e_nname.bv_val ); 517 } 518 519 e->e_name.bv_len = rlen - 1; 520 e->e_nname.bv_len = nrlen - 1; 521 e->e_name.bv_val = ch_malloc(rlen); 522 e->e_nname.bv_val = ch_malloc(nrlen); 523 ptr = e->e_name.bv_val; 524 nptr = e->e_nname.bv_val; 525 for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) { 526 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val); 527 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val); 528 if ( ei->bei_parent ) { 529 *ptr++ = ','; 530 *nptr++ = ','; 531 } 532 } 533 BEI(e)->bei_modrdns = max; 534 if ( ptr > e->e_name.bv_val ) ptr[-1] = '\0'; 535 if ( nptr > e->e_nname.bv_val ) nptr[-1] = '\0'; 536 537 return 0; 538} 539 540/* We add two elements to the DN2ID database - a data item under the parent's 541 * entryID containing the child's RDN and entryID, and an item under the 542 * child's entryID containing the parent's entryID. 543 */ 544int 545hdb_dn2id_add( 546 Operation *op, 547 DB_TXN *txn, 548 EntryInfo *eip, 549 Entry *e ) 550{ 551 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 552 DB *db = bdb->bi_dn2id->bdi_db; 553 DBT key, data; 554 ID nid; 555 int rc, rlen, nrlen; 556 diskNode *d; 557 char *ptr; 558 559 Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_add 0x%lx: \"%s\"\n", 560 e->e_id, e->e_ndn, 0 ); 561 562 nrlen = dn_rdnlen( op->o_bd, &e->e_nname ); 563 if (nrlen) { 564 rlen = dn_rdnlen( op->o_bd, &e->e_name ); 565 } else { 566 nrlen = e->e_nname.bv_len; 567 rlen = e->e_name.bv_len; 568 } 569 570 d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx); 571 d->nrdnlen[1] = nrlen & 0xff; 572 d->nrdnlen[0] = (nrlen >> 8) | 0x80; 573 ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen ); 574 *ptr++ = '\0'; 575 ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen ); 576 *ptr++ = '\0'; 577 BDB_ID2DISK( e->e_id, ptr ); 578 579 DBTzero(&key); 580 DBTzero(&data); 581 key.size = sizeof(ID); 582 key.flags = DB_DBT_USERMEM; 583 BDB_ID2DISK( eip->bei_id, &nid ); 584 585 key.data = &nid; 586 587 /* Need to make dummy root node once. Subsequent attempts 588 * will fail harmlessly. 589 */ 590 if ( eip->bei_id == 0 ) { 591 diskNode dummy = {{0, 0}, "", "", ""}; 592 data.data = &dummy; 593 data.size = sizeof(diskNode); 594 data.flags = DB_DBT_USERMEM; 595 596 db->put( db, txn, &key, &data, DB_NODUPDATA ); 597 } 598 599 data.data = d; 600 data.size = sizeof(diskNode) + rlen + nrlen; 601 data.flags = DB_DBT_USERMEM; 602 603 rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); 604 605 if (rc == 0) { 606 BDB_ID2DISK( e->e_id, &nid ); 607 BDB_ID2DISK( eip->bei_id, ptr ); 608 d->nrdnlen[0] ^= 0x80; 609 610 rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); 611 } 612 613 /* Update all parents' IDL cache entries */ 614 if ( rc == 0 && bdb->bi_idl_cache_size ) { 615 ID tmp[2]; 616 char *ptr = ((char *)&tmp[1])-1; 617 key.data = ptr; 618 key.size = sizeof(ID)+1; 619 tmp[1] = eip->bei_id; 620 *ptr = DN_ONE_PREFIX; 621 bdb_idl_cache_add_id( bdb, db, &key, e->e_id ); 622 if ( eip->bei_parent ) { 623 *ptr = DN_SUBTREE_PREFIX; 624 for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) { 625 tmp[1] = eip->bei_id; 626 bdb_idl_cache_add_id( bdb, db, &key, e->e_id ); 627 } 628 /* Handle DB with empty suffix */ 629 if ( !op->o_bd->be_suffix[0].bv_len && eip ) { 630 tmp[1] = eip->bei_id; 631 bdb_idl_cache_add_id( bdb, db, &key, e->e_id ); 632 } 633 } 634 } 635 636 op->o_tmpfree( d, op->o_tmpmemctx ); 637 Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 ); 638 639 return rc; 640} 641 642int 643hdb_dn2id_delete( 644 Operation *op, 645 DB_TXN *txn, 646 EntryInfo *eip, 647 Entry *e ) 648{ 649 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 650 DB *db = bdb->bi_dn2id->bdi_db; 651 DBT key, data; 652 DBC *cursor; 653 diskNode *d; 654 int rc; 655 ID nid; 656 unsigned char dlen[2]; 657 DB_LOCK lock; 658 659 Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_delete 0x%lx: \"%s\"\n", 660 e->e_id, e->e_ndn, 0 ); 661 662 DBTzero(&key); 663 key.size = sizeof(ID); 664 key.ulen = key.size; 665 key.flags = DB_DBT_USERMEM; 666 BDB_ID2DISK( eip->bei_id, &nid ); 667 668 DBTzero(&data); 669 data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len - sizeof(ID) - 1; 670 data.ulen = data.size; 671 data.dlen = data.size; 672 data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; 673 674 key.data = &nid; 675 676 d = op->o_tmpalloc( data.size, op->o_tmpmemctx ); 677 d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff; 678 d->nrdnlen[0] = (BEI(e)->bei_nrdn.bv_len >> 8) | 0x80; 679 dlen[0] = d->nrdnlen[0]; 680 dlen[1] = d->nrdnlen[1]; 681 memcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val, BEI(e)->bei_nrdn.bv_len+1 ); 682 data.data = d; 683 684 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); 685 if ( rc ) goto func_leave; 686 687 /* We hold this lock until the TXN completes */ 688 rc = bdb_dn2id_lock( bdb, &e->e_nname, 1, txn, &lock ); 689 if ( rc ) goto nolock; 690 691 /* Delete our ID from the parent's list */ 692 rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE ); 693 if ( rc == 0 ) { 694 if ( dlen[1] == d->nrdnlen[1] && dlen[0] == d->nrdnlen[0] && 695 !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val )) 696 rc = cursor->c_del( cursor, 0 ); 697 else 698 rc = DB_NOTFOUND; 699 } 700 701 /* Delete our ID from the tree. With sorted duplicates, this 702 * will leave any child nodes still hanging around. This is OK 703 * for modrdn, which will add our info back in later. 704 */ 705 if ( rc == 0 ) { 706 BDB_ID2DISK( e->e_id, &nid ); 707 rc = cursor->c_get( cursor, &key, &data, DB_SET ); 708 if ( rc == 0 ) 709 rc = cursor->c_del( cursor, 0 ); 710 } 711 712nolock: 713 cursor->c_close( cursor ); 714func_leave: 715 op->o_tmpfree( d, op->o_tmpmemctx ); 716 717 /* Delete IDL cache entries */ 718 if ( rc == 0 && bdb->bi_idl_cache_size ) { 719 ID tmp[2]; 720 char *ptr = ((char *)&tmp[1])-1; 721 key.data = ptr; 722 key.size = sizeof(ID)+1; 723 tmp[1] = eip->bei_id; 724 *ptr = DN_ONE_PREFIX; 725 bdb_idl_cache_del_id( bdb, db, &key, e->e_id ); 726 if ( eip ->bei_parent ) { 727 *ptr = DN_SUBTREE_PREFIX; 728 for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) { 729 tmp[1] = eip->bei_id; 730 bdb_idl_cache_del_id( bdb, db, &key, e->e_id ); 731 } 732 /* Handle DB with empty suffix */ 733 if ( !op->o_bd->be_suffix[0].bv_len && eip ) { 734 tmp[1] = eip->bei_id; 735 bdb_idl_cache_del_id( bdb, db, &key, e->e_id ); 736 } 737 } 738 } 739 Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 ); 740 return rc; 741} 742 743 744int 745hdb_dn2id( 746 Operation *op, 747 struct berval *in, 748 EntryInfo *ei, 749 DB_TXN *txn, 750 DB_LOCK *lock ) 751{ 752 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 753 DB *db = bdb->bi_dn2id->bdi_db; 754 DBT key, data; 755 DBC *cursor; 756 int rc = 0, nrlen; 757 diskNode *d; 758 char *ptr; 759 unsigned char dlen[2]; 760 ID idp, parentID; 761 762 Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id(\"%s\")\n", in->bv_val, 0, 0 ); 763 764 nrlen = dn_rdnlen( op->o_bd, in ); 765 if (!nrlen) nrlen = in->bv_len; 766 767 DBTzero(&key); 768 key.size = sizeof(ID); 769 key.data = &idp; 770 key.ulen = sizeof(ID); 771 key.flags = DB_DBT_USERMEM; 772 parentID = ( ei->bei_parent != NULL ) ? ei->bei_parent->bei_id : 0; 773 BDB_ID2DISK( parentID, &idp ); 774 775 DBTzero(&data); 776 data.size = sizeof(diskNode) + nrlen - sizeof(ID) - 1; 777 data.ulen = data.size * 3; 778 data.dlen = data.ulen; 779 data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; 780 781 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); 782 if ( rc ) return rc; 783 784 d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx ); 785 d->nrdnlen[1] = nrlen & 0xff; 786 d->nrdnlen[0] = (nrlen >> 8) | 0x80; 787 dlen[0] = d->nrdnlen[0]; 788 dlen[1] = d->nrdnlen[1]; 789 ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen ); 790 *ptr = '\0'; 791 data.data = d; 792 793 rc = bdb_dn2id_lock( bdb, in, 0, txn, lock ); 794 if ( rc ) goto func_leave; 795 796 rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE ); 797 if ( rc == 0 && (dlen[1] != d->nrdnlen[1] || dlen[0] != d->nrdnlen[0] || 798 strncmp( d->nrdn, in->bv_val, nrlen ))) { 799 rc = DB_NOTFOUND; 800 } 801 if ( rc == 0 ) { 802 ptr = (char *) data.data + data.size - sizeof(ID); 803 BDB_DISK2ID( ptr, &ei->bei_id ); 804 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen; 805 ptr = d->nrdn + nrlen + 1; 806 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn ); 807 if ( ei->bei_parent != NULL && !ei->bei_parent->bei_dkids ) { 808 db_recno_t dkids; 809 /* How many children does the parent have? */ 810 /* FIXME: do we need to lock the parent 811 * entryinfo? Seems safe... 812 */ 813 cursor->c_count( cursor, &dkids, 0 ); 814 ei->bei_parent->bei_dkids = dkids; 815 } 816 } 817 818func_leave: 819 cursor->c_close( cursor ); 820 op->o_tmpfree( d, op->o_tmpmemctx ); 821 if( rc != 0 ) { 822 Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: get failed: %s (%d)\n", 823 db_strerror( rc ), rc, 0 ); 824 } else { 825 Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: got id=0x%lx\n", 826 ei->bei_id, 0, 0 ); 827 } 828 829 return rc; 830} 831 832int 833hdb_dn2id_parent( 834 Operation *op, 835 DB_TXN *txn, 836 EntryInfo *ei, 837 ID *idp ) 838{ 839 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 840 DB *db = bdb->bi_dn2id->bdi_db; 841 DBT key, data; 842 DBC *cursor; 843 int rc = 0; 844 diskNode *d; 845 char *ptr; 846 ID nid; 847 848 DBTzero(&key); 849 key.size = sizeof(ID); 850 key.data = &nid; 851 key.ulen = sizeof(ID); 852 key.flags = DB_DBT_USERMEM; 853 BDB_ID2DISK( ei->bei_id, &nid ); 854 855 DBTzero(&data); 856 data.flags = DB_DBT_USERMEM; 857 858 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); 859 if ( rc ) return rc; 860 861 data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2); 862 d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx ); 863 data.data = d; 864 865 rc = cursor->c_get( cursor, &key, &data, DB_SET ); 866 if ( rc == 0 ) { 867 if (d->nrdnlen[0] & 0x80) { 868 rc = LDAP_OTHER; 869 } else { 870 db_recno_t dkids; 871 ptr = (char *) data.data + data.size - sizeof(ID); 872 BDB_DISK2ID( ptr, idp ); 873 ei->bei_nrdn.bv_len = (d->nrdnlen[0] << 8) | d->nrdnlen[1]; 874 ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn ); 875 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - 876 ei->bei_nrdn.bv_len; 877 ptr = d->nrdn + ei->bei_nrdn.bv_len + 1; 878 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn ); 879 /* How many children does this node have? */ 880 cursor->c_count( cursor, &dkids, 0 ); 881 ei->bei_dkids = dkids; 882 } 883 } 884 cursor->c_close( cursor ); 885 op->o_tmpfree( d, op->o_tmpmemctx ); 886 return rc; 887} 888 889int 890hdb_dn2id_children( 891 Operation *op, 892 DB_TXN *txn, 893 Entry *e ) 894{ 895 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 896 DB *db = bdb->bi_dn2id->bdi_db; 897 DBT key, data; 898 DBC *cursor; 899 int rc; 900 ID id; 901 diskNode d; 902 903 DBTzero(&key); 904 key.size = sizeof(ID); 905 key.data = &e->e_id; 906 key.flags = DB_DBT_USERMEM; 907 BDB_ID2DISK( e->e_id, &id ); 908 909 /* IDL cache is in host byte order */ 910 if ( bdb->bi_idl_cache_size ) { 911 rc = bdb_idl_cache_get( bdb, db, &key, NULL ); 912 if ( rc != LDAP_NO_SUCH_OBJECT ) { 913 return rc; 914 } 915 } 916 917 key.data = &id; 918 DBTzero(&data); 919 data.data = &d; 920 data.ulen = sizeof(d); 921 data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; 922 data.dlen = sizeof(d); 923 924 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); 925 if ( rc ) return rc; 926 927 rc = cursor->c_get( cursor, &key, &data, DB_SET ); 928 if ( rc == 0 ) { 929 db_recno_t dkids; 930 rc = cursor->c_count( cursor, &dkids, 0 ); 931 if ( rc == 0 ) { 932 BEI(e)->bei_dkids = dkids; 933 if ( dkids < 2 ) rc = DB_NOTFOUND; 934 } 935 } 936 cursor->c_close( cursor ); 937 return rc; 938} 939 940/* bdb_dn2idl: 941 * We can't just use bdb_idl_fetch_key because 942 * 1 - our data items are longer than just an entry ID 943 * 2 - our data items are sorted alphabetically by nrdn, not by ID. 944 * 945 * We descend the tree recursively, so we define this cookie 946 * to hold our necessary state information. The bdb_dn2idl_internal 947 * function uses this cookie when calling itself. 948 */ 949 950struct dn2id_cookie { 951 struct bdb_info *bdb; 952 Operation *op; 953 DB_TXN *txn; 954 EntryInfo *ei; 955 ID *ids; 956 ID *tmp; 957 ID *buf; 958 DB *db; 959 DBC *dbc; 960 DBT key; 961 DBT data; 962 ID dbuf; 963 ID id; 964 ID nid; 965 int rc; 966 int depth; 967 char need_sort; 968 char prefix; 969}; 970 971static int 972apply_func( 973 void *data, 974 void *arg ) 975{ 976 EntryInfo *ei = data; 977 ID *idl = arg; 978 979 bdb_idl_append_one( idl, ei->bei_id ); 980 return 0; 981} 982 983static int 984hdb_dn2idl_internal( 985 struct dn2id_cookie *cx 986) 987{ 988 BDB_IDL_ZERO( cx->tmp ); 989 990 if ( cx->bdb->bi_idl_cache_size ) { 991 char *ptr = ((char *)&cx->id)-1; 992 993 cx->key.data = ptr; 994 cx->key.size = sizeof(ID)+1; 995 if ( cx->prefix == DN_SUBTREE_PREFIX ) { 996 ID *ids = cx->depth ? cx->tmp : cx->ids; 997 *ptr = cx->prefix; 998 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, ids); 999 if ( cx->rc == LDAP_SUCCESS ) { 1000 if ( cx->depth ) { 1001 bdb_idl_append( cx->ids, cx->tmp ); 1002 cx->need_sort = 1; 1003 } 1004 return cx->rc; 1005 } 1006 } 1007 *ptr = DN_ONE_PREFIX; 1008 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp); 1009 if ( cx->rc == LDAP_SUCCESS ) { 1010 goto gotit; 1011 } 1012 if ( cx->rc == DB_NOTFOUND ) { 1013 return cx->rc; 1014 } 1015 } 1016 1017 bdb_cache_entryinfo_lock( cx->ei ); 1018 1019 /* If number of kids in the cache differs from on-disk, load 1020 * up all the kids from the database 1021 */ 1022 if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) { 1023 EntryInfo ei; 1024 db_recno_t dkids = cx->ei->bei_dkids; 1025 ei.bei_parent = cx->ei; 1026 1027 /* Only one thread should load the cache */ 1028 while ( cx->ei->bei_state & CACHE_ENTRY_ONELEVEL ) { 1029 bdb_cache_entryinfo_unlock( cx->ei ); 1030 ldap_pvt_thread_yield(); 1031 bdb_cache_entryinfo_lock( cx->ei ); 1032 if ( cx->ei->bei_ckids+1 == cx->ei->bei_dkids ) { 1033 goto synced; 1034 } 1035 } 1036 1037 cx->ei->bei_state |= CACHE_ENTRY_ONELEVEL; 1038 1039 bdb_cache_entryinfo_unlock( cx->ei ); 1040 1041 cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc, 1042 cx->bdb->bi_db_opflags ); 1043 if ( cx->rc ) 1044 goto done_one; 1045 1046 cx->data.data = &cx->dbuf; 1047 cx->data.ulen = sizeof(ID); 1048 cx->data.dlen = sizeof(ID); 1049 cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; 1050 1051 /* The first item holds the parent ID. Ignore it. */ 1052 cx->key.data = &cx->nid; 1053 cx->key.size = sizeof(ID); 1054 cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET ); 1055 if ( cx->rc ) { 1056 cx->dbc->c_close( cx->dbc ); 1057 goto done_one; 1058 } 1059 1060 /* If the on-disk count is zero we've never checked it. 1061 * Count it now. 1062 */ 1063 if ( !dkids ) { 1064 cx->dbc->c_count( cx->dbc, &dkids, 0 ); 1065 cx->ei->bei_dkids = dkids; 1066 } 1067 1068 cx->data.data = cx->buf; 1069 cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID); 1070 cx->data.flags = DB_DBT_USERMEM; 1071 1072 if ( dkids > 1 ) { 1073 /* Fetch the rest of the IDs in a loop... */ 1074 while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, 1075 DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) { 1076 u_int8_t *j; 1077 size_t len; 1078 void *ptr; 1079 DB_MULTIPLE_INIT( ptr, &cx->data ); 1080 while (ptr) { 1081 DB_MULTIPLE_NEXT( ptr, &cx->data, j, len ); 1082 if (j) { 1083 EntryInfo *ei2; 1084 diskNode *d = (diskNode *)j; 1085 short nrlen; 1086 1087 BDB_DISK2ID( j + len - sizeof(ID), &ei.bei_id ); 1088 nrlen = ((d->nrdnlen[0] ^ 0x80) << 8) | d->nrdnlen[1]; 1089 ei.bei_nrdn.bv_len = nrlen; 1090 /* nrdn/rdn are set in-place. 1091 * hdb_cache_load will copy them as needed 1092 */ 1093 ei.bei_nrdn.bv_val = d->nrdn; 1094 ei.bei_rdn.bv_len = len - sizeof(diskNode) 1095 - ei.bei_nrdn.bv_len; 1096 ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1; 1097 bdb_idl_append_one( cx->tmp, ei.bei_id ); 1098 hdb_cache_load( cx->bdb, &ei, &ei2 ); 1099 } 1100 } 1101 } 1102 } 1103 1104 cx->rc = cx->dbc->c_close( cx->dbc ); 1105done_one: 1106 bdb_cache_entryinfo_lock( cx->ei ); 1107 cx->ei->bei_state &= ~CACHE_ENTRY_ONELEVEL; 1108 bdb_cache_entryinfo_unlock( cx->ei ); 1109 if ( cx->rc ) 1110 return cx->rc; 1111 1112 } else { 1113 /* The in-memory cache is in sync with the on-disk data. 1114 * do we have any kids? 1115 */ 1116synced: 1117 cx->rc = 0; 1118 if ( cx->ei->bei_ckids > 0 ) { 1119 /* Walk the kids tree; order is irrelevant since bdb_idl_sort 1120 * will sort it later. 1121 */ 1122 avl_apply( cx->ei->bei_kids, apply_func, 1123 cx->tmp, -1, AVL_POSTORDER ); 1124 } 1125 bdb_cache_entryinfo_unlock( cx->ei ); 1126 } 1127 1128 if ( !BDB_IDL_IS_RANGE( cx->tmp ) && cx->tmp[0] > 3 ) 1129 bdb_idl_sort( cx->tmp, cx->buf ); 1130 if ( cx->bdb->bi_idl_cache_max_size && !BDB_IDL_IS_ZERO( cx->tmp )) { 1131 char *ptr = ((char *)&cx->id)-1; 1132 cx->key.data = ptr; 1133 cx->key.size = sizeof(ID)+1; 1134 *ptr = DN_ONE_PREFIX; 1135 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc ); 1136 } 1137 1138gotit: 1139 if ( !BDB_IDL_IS_ZERO( cx->tmp )) { 1140 if ( cx->prefix == DN_SUBTREE_PREFIX ) { 1141 bdb_idl_append( cx->ids, cx->tmp ); 1142 cx->need_sort = 1; 1143 if ( !(cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS)) { 1144 ID *save, idcurs; 1145 EntryInfo *ei = cx->ei; 1146 int nokids = 1; 1147 save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ), 1148 cx->op->o_tmpmemctx ); 1149 BDB_IDL_CPY( save, cx->tmp ); 1150 1151 idcurs = 0; 1152 cx->depth++; 1153 for ( cx->id = bdb_idl_first( save, &idcurs ); 1154 cx->id != NOID; 1155 cx->id = bdb_idl_next( save, &idcurs )) { 1156 EntryInfo *ei2; 1157 cx->ei = NULL; 1158 if ( bdb_cache_find_id( cx->op, cx->txn, cx->id, &cx->ei, 1159 ID_NOENTRY, NULL )) 1160 continue; 1161 if ( cx->ei ) { 1162 ei2 = cx->ei; 1163 if ( !( ei2->bei_state & CACHE_ENTRY_NO_KIDS )) { 1164 BDB_ID2DISK( cx->id, &cx->nid ); 1165 hdb_dn2idl_internal( cx ); 1166 if ( !BDB_IDL_IS_ZERO( cx->tmp )) 1167 nokids = 0; 1168 } 1169 bdb_cache_entryinfo_lock( ei2 ); 1170 ei2->bei_finders--; 1171 bdb_cache_entryinfo_unlock( ei2 ); 1172 } 1173 } 1174 cx->depth--; 1175 cx->op->o_tmpfree( save, cx->op->o_tmpmemctx ); 1176 if ( nokids ) { 1177 bdb_cache_entryinfo_lock( ei ); 1178 ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS; 1179 bdb_cache_entryinfo_unlock( ei ); 1180 } 1181 } 1182 /* Make sure caller knows it had kids! */ 1183 cx->tmp[0]=1; 1184 1185 cx->rc = 0; 1186 } else { 1187 BDB_IDL_CPY( cx->ids, cx->tmp ); 1188 } 1189 } 1190 return cx->rc; 1191} 1192 1193int 1194hdb_dn2idl( 1195 Operation *op, 1196 DB_TXN *txn, 1197 struct berval *ndn, 1198 EntryInfo *ei, 1199 ID *ids, 1200 ID *stack ) 1201{ 1202 struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private; 1203 struct dn2id_cookie cx; 1204 1205 Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl(\"%s\")\n", 1206 ndn->bv_val, 0, 0 ); 1207 1208#ifndef BDB_MULTIPLE_SUFFIXES 1209 if ( op->ors_scope != LDAP_SCOPE_ONELEVEL && 1210 ( ei->bei_id == 0 || 1211 ( ei->bei_parent->bei_id == 0 && op->o_bd->be_suffix[0].bv_len ))) 1212 { 1213 BDB_IDL_ALL( bdb, ids ); 1214 return 0; 1215 } 1216#endif 1217 1218 cx.id = ei->bei_id; 1219 BDB_ID2DISK( cx.id, &cx.nid ); 1220 cx.ei = ei; 1221 cx.bdb = bdb; 1222 cx.db = cx.bdb->bi_dn2id->bdi_db; 1223 cx.prefix = (op->ors_scope == LDAP_SCOPE_ONELEVEL) ? 1224 DN_ONE_PREFIX : DN_SUBTREE_PREFIX; 1225 cx.ids = ids; 1226 cx.tmp = stack; 1227 cx.buf = stack + BDB_IDL_UM_SIZE; 1228 cx.op = op; 1229 cx.txn = txn; 1230 cx.need_sort = 0; 1231 cx.depth = 0; 1232 1233 if ( cx.prefix == DN_SUBTREE_PREFIX ) { 1234 ids[0] = 1; 1235 ids[1] = cx.id; 1236 } else { 1237 BDB_IDL_ZERO( ids ); 1238 } 1239 if ( cx.ei->bei_state & CACHE_ENTRY_NO_KIDS ) 1240 return LDAP_SUCCESS; 1241 1242 DBTzero(&cx.key); 1243 cx.key.ulen = sizeof(ID); 1244 cx.key.size = sizeof(ID); 1245 cx.key.flags = DB_DBT_USERMEM; 1246 1247 DBTzero(&cx.data); 1248 1249 hdb_dn2idl_internal(&cx); 1250 if ( cx.need_sort ) { 1251 char *ptr = ((char *)&cx.id)-1; 1252 if ( !BDB_IDL_IS_RANGE( cx.ids ) && cx.ids[0] > 3 ) 1253 bdb_idl_sort( cx.ids, cx.tmp ); 1254 cx.key.data = ptr; 1255 cx.key.size = sizeof(ID)+1; 1256 *ptr = cx.prefix; 1257 cx.id = ei->bei_id; 1258 if ( cx.bdb->bi_idl_cache_max_size ) 1259 bdb_idl_cache_put( cx.bdb, cx.db, &cx.key, cx.ids, cx.rc ); 1260 } 1261 1262 if ( cx.rc == DB_NOTFOUND ) 1263 cx.rc = LDAP_SUCCESS; 1264 1265 return cx.rc; 1266} 1267#endif /* BDB_HIER */ 1268