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