1 /* id2entry.c - routines to deal with the id2entry database */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2012 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
20 #include <ac/string.h>
25 typedef struct Ecount {
32 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
34 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data,
36 static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals );
38 #define ADD_FLAGS (MDB_NOOVERWRITE|MDB_APPEND)
40 static int mdb_id2entry_put(
47 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
52 /* We only store rdns, and they go in the dn2id database. */
54 key.mv_data = &e->e_id;
55 key.mv_size = sizeof(ID);
57 rc = mdb_entry_partsize( mdb, txn, e, &ec );
64 data.mv_size = ec.len;
66 rc = mdb_cursor_put( mc, &key, &data, flag );
68 rc = mdb_put( txn, mdb->mi_id2entry, &key, &data, flag );
69 if (rc == MDB_SUCCESS) {
70 rc = mdb_entry_encode( op, e, &data, &ec );
71 if( rc != LDAP_SUCCESS )
75 /* Was there a hole from slapadd? */
76 if ( (flag & MDB_NOOVERWRITE) && data.mv_size == 0 ) {
80 Debug( LDAP_DEBUG_ANY,
81 "mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n",
84 if ( rc != MDB_KEYEXIST )
91 * This routine adds (or updates) an entry on disk.
92 * The cache should be already be updated.
102 return mdb_id2entry_put(op, txn, mc, e, ADD_FLAGS);
105 int mdb_id2entry_update(
111 return mdb_id2entry_put(op, txn, mc, e, 0);
120 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
127 key.mv_size = sizeof(ID);
130 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
131 if ( rc == MDB_NOTFOUND ) {
132 /* Looking for root entry on an empty-dn suffix? */
133 if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) {
134 struct berval gluebv = BER_BVC("glue");
135 Entry *r = mdb_entry_alloc(op, 2, 4);
136 Attribute *a = r->e_attrs;
140 r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
142 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
143 a->a_desc = slap_schema.si_ad_objectClass;
144 a->a_nvals = a->a_vals;
151 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
152 a->a_desc = slap_schema.si_ad_structuralObjectClass;
154 a->a_nvals = a->a_vals;
165 rc = mdb_entry_decode( op, &data, e );
169 (*e)->e_name.bv_val = NULL;
170 (*e)->e_nname.bv_val = NULL;
175 int mdb_id2entry_delete(
180 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
181 MDB_dbi dbi = mdb->mi_id2entry;
185 key.mv_data = &e->e_id;
186 key.mv_size = sizeof(ID);
188 /* delete from database */
189 rc = mdb_del( tid, dbi, &key, NULL );
194 static Entry * mdb_entry_alloc(
199 Entry *e = op->o_tmpalloc( sizeof(Entry) +
200 nattrs * sizeof(Attribute) +
201 nvals * sizeof(struct berval), op->o_tmpmemctx );
202 BER_BVZERO(&e->e_bv);
205 e->e_attrs = (Attribute *)(e+1);
206 e->e_attrs->a_vals = (struct berval *)(e->e_attrs+nattrs);
214 int mdb_entry_return(
219 if ( e->e_private ) {
221 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
222 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
223 op->o_tmpfree( e, op->o_tmpmemctx );
225 ch_free( e->e_nname.bv_val );
226 ch_free( e->e_name.bv_val );
235 int mdb_entry_release(
240 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
241 struct mdb_op_info *moi = NULL;
244 /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
245 SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
247 mdb_entry_return( op, e );
248 if ( slapMode == SLAP_SERVER_MODE ) {
250 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
251 if ( oex->oe_key == mdb ) {
252 moi = (mdb_op_info *)oex;
253 /* If it was setup by entry_get we should probably free it */
254 if ( moi->moi_flag & MOI_FREEIT ) {
256 if ( moi->moi_ref < 1 ) {
257 mdb_txn_reset( moi->moi_txn );
259 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
260 op->o_tmpfree( moi, op->o_tmpmemctx );
271 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
277 AttributeDescription *at,
281 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
282 struct mdb_op_info *moi = NULL;
286 const char *at_name = at ? at->ad_cname.bv_val : "(null)";
288 Debug( LDAP_DEBUG_ARGS,
289 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 );
290 Debug( LDAP_DEBUG_ARGS,
291 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
292 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
294 rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
299 /* can we find entry */
300 rc = mdb_dn2entry( op, txn, NULL, ndn, &e, 0 );
306 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
309 Debug( LDAP_DEBUG_ACL,
310 "=> mdb_entry_get: cannot find entry: \"%s\"\n",
312 rc = LDAP_NO_SUCH_OBJECT;
316 Debug( LDAP_DEBUG_ACL,
317 "=> mdb_entry_get: found entry: \"%s\"\n",
320 if ( oc && !is_entry_objectclass( e, oc, 0 )) {
321 Debug( LDAP_DEBUG_ACL,
322 "<= mdb_entry_get: failed to find objectClass %s\n",
323 oc->soc_cname.bv_val, 0, 0 );
324 rc = LDAP_NO_SUCH_ATTRIBUTE;
328 /* NOTE: attr_find() or attrs_find()? */
329 if ( at && attr_find( e->e_attrs, at ) == NULL ) {
330 Debug( LDAP_DEBUG_ACL,
331 "<= mdb_entry_get: failed to find attribute %s\n",
332 at->ad_cname.bv_val, 0, 0 );
333 rc = LDAP_NO_SUCH_ATTRIBUTE;
338 if( rc != LDAP_SUCCESS ) {
341 mdb_entry_return( op, e );
343 if (moi->moi_ref == 1) {
344 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
345 mdb_txn_reset( txn );
346 op->o_tmpfree( moi, op->o_tmpmemctx );
352 Debug( LDAP_DEBUG_TRACE,
353 "mdb_entry_get: rc=%d\n",
359 mdb_reader_free( void *key, void *data )
363 if ( txn ) mdb_txn_abort( txn );
366 /* free up any keys used by the main thread */
368 mdb_reader_flush( MDB_env *env )
371 void *ctx = ldap_pvt_thread_pool_context();
373 if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
374 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
375 mdb_reader_free( env, data );
380 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
385 mdb_op_info *moi = NULL;
388 assert( op != NULL );
390 if ( !mdb || !moip ) return -1;
392 /* If no op was provided, try to find the ctx anyway... */
394 ctx = op->o_threadctx;
396 ctx = ldap_pvt_thread_pool_context();
400 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
401 if ( oex->oe_key == mdb ) break;
403 moi = (mdb_op_info *)oex;
411 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
413 moi = ch_malloc(sizeof(mdb_op_info));
415 moi->moi_flag = MOI_FREEIT;
418 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
419 moi->moi_oe.oe_key = mdb;
425 /* This op started as a reader, but now wants to write. */
426 if ( moi->moi_flag & MOI_READER ) {
428 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
430 /* This op is continuing an existing write txn */
434 if ( !moi->moi_txn ) {
435 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &moi->moi_txn );
437 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
438 mdb_strerror(rc), rc, 0 );
445 /* OK, this is a reader */
446 if ( !moi->moi_txn ) {
448 /* Shouldn't happen unless we're single-threaded */
449 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
451 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
452 mdb_strerror(rc), rc, 0 );
456 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
457 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
459 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
460 mdb_strerror(rc), rc, 0 );
464 if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
465 data, mdb_reader_free, NULL, NULL ) ) ) {
466 mdb_txn_abort( moi->moi_txn );
468 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
476 moi->moi_flag |= MOI_READER;
478 if ( moi->moi_ref < 1 ) {
482 mdb_txn_renew( moi->moi_txn );
491 /* Count up the sizes of the components of an entry */
492 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
496 int i, nat = 0, nval = 0, nnval = 0;
499 len = 4*sizeof(int); /* nattrs, nvals, ocflags, offset */
500 for (a=e->e_attrs; a; a=a->a_next) {
501 /* For AttributeDesc, we only store the attr index */
503 if (a->a_desc->ad_index >= MDB_MAXADS) {
504 Debug( LDAP_DEBUG_ANY, "mdb_entry_partsize: too many AttributeDescriptions used\n",
508 if (!mdb->mi_adxs[a->a_desc->ad_index]) {
509 int rc = mdb_ad_get(mdb, txn, a->a_desc);
513 len += 2*sizeof(int); /* AD index, numvals */
514 nval += a->a_numvals + 1; /* empty berval at end */
515 for (i=0; i<a->a_numvals; i++) {
516 len += a->a_vals[i].bv_len + 1 + sizeof(int); /* len */
518 if (a->a_nvals != a->a_vals) {
519 nval += a->a_numvals + 1;
521 for (i=0; i<a->a_numvals; i++) {
522 len += a->a_nvals[i].bv_len + 1 + sizeof(int);;
527 len = (len + sizeof(ID)-1) & ~(sizeof(ID)-1);
531 eh->offset = nat + nval - nnval;
535 #define HIGH_BIT (1<<(sizeof(unsigned int)*CHAR_BIT-1))
537 /* Flatten an Entry into a buffer. The buffer starts with the count of the
538 * number of attributes in the entry, the total number of values in the
539 * entry, and the e_ocflags. It then contains a list of integers for each
540 * attribute. For each attribute the first integer gives the index of the
541 * matching AttributeDescription, followed by the number of values in the
542 * attribute. If the high bit is set, the attribute also has normalized
543 * values present. (Note - a_numvals is an unsigned int, so this means
544 * it's possible to receive an attribute that we can't encode due to size
545 * overflow. In practice, this should not be an issue.) Then the length
546 * of each value is listed. If there are normalized values, their lengths
547 * come next. This continues for each attribute. After all of the lengths
548 * for the last attribute, the actual values are copied, with a NUL
549 * terminator after each value. The buffer is padded to the sizeof(ID).
550 * The entire buffer size is precomputed so that a single malloc can be
553 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh)
555 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
562 Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n",
563 (long) e->e_id, e->e_dn, 0 );
565 /* make sure e->e_ocflags is set */
566 if (is_entry_referral(e))
569 lp = (unsigned int *)data->mv_data;
572 *lp++ = (unsigned int)e->e_ocflags;
574 ptr = (unsigned char *)(lp + eh->offset);
576 for (a=e->e_attrs; a; a=a->a_next) {
577 *lp++ = mdb->mi_adxs[a->a_desc->ad_index];
579 if (a->a_nvals != a->a_vals)
583 for (i=0; a->a_vals[i].bv_val; i++);
584 assert( i == a->a_numvals );
585 for (i=0; i<a->a_numvals; i++) {
586 *lp++ = a->a_vals[i].bv_len;
587 memcpy(ptr, a->a_vals[i].bv_val,
588 a->a_vals[i].bv_len);
589 ptr += a->a_vals[i].bv_len;
592 if (a->a_nvals != a->a_vals) {
593 for (i=0; i<a->a_numvals; i++) {
594 *lp++ = a->a_nvals[i].bv_len;
595 memcpy(ptr, a->a_nvals[i].bv_val,
596 a->a_nvals[i].bv_len);
597 ptr += a->a_nvals[i].bv_len;
604 Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n",
605 (long) e->e_id, e->e_dn, 0 );
610 /* Retrieve an Entry that was stored using entry_encode above.
612 * Note: everything is stored in a single contiguous block, so
613 * you can not free individual attributes or names from this
614 * structure. Attempting to do so will likely corrupt memory.
617 int mdb_entry_decode(Operation *op, MDB_val *data, Entry **e)
619 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
620 int i, j, nattrs, nvals;
625 AttributeDescription *ad;
626 unsigned int *lp = (unsigned int *)data->mv_data;
630 Debug( LDAP_DEBUG_TRACE,
631 "=> mdb_entry_decode:\n",
636 x = mdb_entry_alloc(op, nattrs, nvals);
637 x->e_ocflags = *lp++;
644 ptr = (unsigned char *)(lp + i);
646 for (;nattrs>0; nattrs--) {
648 a->a_desc = mdb->mi_ads[*lp++];
649 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
650 a->a_numvals = *lp++;
651 if (a->a_numvals & HIGH_BIT) {
652 a->a_numvals ^= HIGH_BIT;
656 for (i=0; i<a->a_numvals; i++) {
657 bptr->bv_len = *lp++;;
658 bptr->bv_val = (char *)ptr;
659 ptr += bptr->bv_len+1;
668 for (i=0; i<a->a_numvals; i++) {
669 bptr->bv_len = *lp++;
670 bptr->bv_val = (char *)ptr;
671 ptr += bptr->bv_len+1;
678 a->a_nvals = a->a_vals;
680 /* FIXME: This is redundant once a sorted entry is saved into the DB */
681 if ( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
682 rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
683 if ( rc == LDAP_SUCCESS ) {
684 a->a_flags |= SLAP_ATTR_SORTED_VALS;
685 } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
686 /* should never happen */
687 Debug( LDAP_DEBUG_ANY,
688 "mdb_entry_decode: attributeType %s value #%d provided more than once\n",
689 a->a_desc->ad_cname.bv_val, j, 0 );
699 Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n",