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-2011 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 static int mdb_entry_encode(Operation *op, MDB_txn *txn, Entry *e, MDB_val *data);
27 static int mdb_id2entry_put(
33 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
34 MDB_dbi dbi = mdb->mi_id2entry;
38 /* We only store rdns, and they go in the dn2id database. */
40 key.mv_data = &e->e_id;
41 key.mv_size = sizeof(ID);
43 rc = mdb_entry_encode( op, tid, e, &data );
44 if( rc != LDAP_SUCCESS ) {
48 rc = mdb_put( tid, dbi, &key, &data, flag );
49 op->o_tmpfree( data.mv_data, op->o_tmpmemctx );
51 Debug( LDAP_DEBUG_ANY,
52 "mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n",
61 * This routine adds (or updates) an entry on disk.
62 * The cache should be already be updated.
71 return mdb_id2entry_put(op, tid, e, MDB_NOOVERWRITE);
74 int mdb_id2entry_update(
79 return mdb_id2entry_put(op, tid, e, 0);
88 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
89 MDB_dbi dbi = mdb->mi_id2entry;
96 key.mv_size = sizeof(ID);
99 rc = mdb_get( tid, dbi, &key, &data );
100 if ( rc == MDB_NOTFOUND ) {
101 /* Looking for root entry on an empty-dn suffix? */
102 if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) {
103 struct berval gluebv = BER_BVC("glue");
104 Entry *r = entry_alloc();
107 attr_merge_one( r, slap_schema.si_ad_objectClass, &gluebv, NULL );
108 attr_merge_one( r, slap_schema.si_ad_structuralObjectClass, &gluebv, NULL );
109 r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
116 rc = mdb_entry_decode( op, &data, e );
120 (*e)->e_name.bv_val = NULL;
121 (*e)->e_nname.bv_val = NULL;
126 int mdb_id2entry_delete(
131 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
132 MDB_dbi dbi = mdb->mi_id2entry;
136 key.mv_data = &e->e_id;
137 key.mv_size = sizeof(ID);
139 /* delete from database */
140 rc = mdb_del( tid, dbi, &key, NULL );
145 int mdb_entry_return(
153 int mdb_entry_release(
158 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
159 struct mdb_op_info *moi = NULL;
162 /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
163 SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
165 mdb_entry_return ( e );
166 if ( slapMode == SLAP_SERVER_MODE ) {
168 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
169 if ( oex->oe_key == mdb ) {
170 moi = (mdb_op_info *)oex;
171 /* If it was setup by entry_get we should probably free it */
172 if ( moi->moi_flag & MOI_FREEIT ) {
174 if ( moi->moi_ref < 1 ) {
175 mdb_txn_reset( moi->moi_txn );
177 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
178 op->o_tmpfree( moi, op->o_tmpmemctx );
189 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
195 AttributeDescription *at,
199 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
200 struct mdb_op_info *moi = NULL;
204 const char *at_name = at ? at->ad_cname.bv_val : "(null)";
206 Debug( LDAP_DEBUG_ARGS,
207 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 );
208 Debug( LDAP_DEBUG_ARGS,
209 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
210 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
212 rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
217 /* can we find entry */
218 rc = mdb_dn2entry( op, txn, ndn, &e, 0 );
224 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
227 Debug( LDAP_DEBUG_ACL,
228 "=> mdb_entry_get: cannot find entry: \"%s\"\n",
230 rc = LDAP_NO_SUCH_OBJECT;
234 Debug( LDAP_DEBUG_ACL,
235 "=> mdb_entry_get: found entry: \"%s\"\n",
238 if ( oc && !is_entry_objectclass( e, oc, 0 )) {
239 Debug( LDAP_DEBUG_ACL,
240 "<= mdb_entry_get: failed to find objectClass %s\n",
241 oc->soc_cname.bv_val, 0, 0 );
242 rc = LDAP_NO_SUCH_ATTRIBUTE;
246 /* NOTE: attr_find() or attrs_find()? */
247 if ( at && attr_find( e->e_attrs, at ) == NULL ) {
248 Debug( LDAP_DEBUG_ACL,
249 "<= mdb_entry_get: failed to find attribute %s\n",
250 at->ad_cname.bv_val, 0, 0 );
251 rc = LDAP_NO_SUCH_ATTRIBUTE;
256 if( rc != LDAP_SUCCESS ) {
259 mdb_entry_return( e );
261 if (moi->moi_ref == 1) {
262 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
263 mdb_txn_reset( txn );
264 op->o_tmpfree( moi, op->o_tmpmemctx );
270 Debug( LDAP_DEBUG_TRACE,
271 "mdb_entry_get: rc=%d\n",
277 mdb_reader_free( void *key, void *data )
281 if ( txn ) mdb_txn_abort( txn );
284 /* free up any keys used by the main thread */
286 mdb_reader_flush( MDB_env *env )
289 void *ctx = ldap_pvt_thread_pool_context();
291 if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
292 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
293 mdb_reader_free( env, data );
298 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
303 mdb_op_info *moi = NULL;
306 assert( op != NULL );
308 if ( !mdb || !moip ) return -1;
310 /* If no op was provided, try to find the ctx anyway... */
312 ctx = op->o_threadctx;
314 ctx = ldap_pvt_thread_pool_context();
318 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
319 if ( oex->oe_key == mdb ) break;
321 moi = (mdb_op_info *)oex;
329 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
331 moi = ch_malloc(sizeof(mdb_op_info));
333 moi->moi_flag = MOI_FREEIT;
336 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
337 moi->moi_oe.oe_key = mdb;
343 /* This op started as a reader, but now wants to write. */
344 if ( moi->moi_flag & MOI_READER ) {
346 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
348 /* This op is continuing an existing write txn */
352 if ( !moi->moi_txn ) {
353 rc = mdb_txn_begin( mdb->mi_dbenv, 0, &moi->moi_txn );
355 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
356 mdb_strerror(rc), rc, 0 );
363 /* OK, this is a reader */
364 if ( !moi->moi_txn ) {
366 /* Shouldn't happen unless we're single-threaded */
367 rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &moi->moi_txn );
369 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
370 mdb_strerror(rc), rc, 0 );
374 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
375 rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &moi->moi_txn );
377 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
378 mdb_strerror(rc), rc, 0 );
382 if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
383 data, mdb_reader_free, NULL, NULL ) ) ) {
384 mdb_txn_abort( moi->moi_txn );
386 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
394 moi->moi_flag |= MOI_READER;
396 if ( moi->moi_ref < 1 ) {
400 mdb_txn_renew( moi->moi_txn );
409 /* This is like a ber_len */
410 #define entry_lenlen(l) (((l) < 0x80) ? 1 : ((l) < 0x100) ? 2 : \
411 ((l) < 0x10000) ? 3 : ((l) < 0x1000000) ? 4 : 5)
414 mdb_entry_putlen(unsigned char **buf, ber_len_t len)
416 ber_len_t lenlen = entry_lenlen(len);
419 **buf = (unsigned char) len;
422 **buf = 0x80 | ((unsigned char) lenlen - 1);
423 for (i=lenlen-1; i>0; i--) {
424 (*buf)[i] = (unsigned char) len;
432 mdb_entry_getlen(unsigned char **buf)
449 /* Count up the sizes of the components of an entry */
450 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
454 int i, nat = 0, nval = 0;
457 for (a=e->e_attrs; a; a=a->a_next) {
458 /* For AttributeDesc, we only store the attr index */
460 if (!mdb->mi_adxs[a->a_desc->ad_index]) {
461 int rc = mdb_ad_get(mdb, txn, a->a_desc);
465 len += entry_lenlen(mdb->mi_adxs[a->a_desc->ad_index]);
466 for (i=0; a->a_vals[i].bv_val; i++) {
468 len += a->a_vals[i].bv_len + 1;
469 len += entry_lenlen(a->a_vals[i].bv_len);
471 len += entry_lenlen(i);
472 nval++; /* empty berval at end */
473 if (a->a_nvals != a->a_vals) {
474 for (i=0; a->a_nvals[i].bv_val; i++) {
476 len += a->a_nvals[i].bv_len + 1;
477 len += entry_lenlen(a->a_nvals[i].bv_len);
479 len += entry_lenlen(i); /* i nvals */
482 len += entry_lenlen(0); /* 0 nvals */
485 len += entry_lenlen(e->e_ocflags);
486 len += entry_lenlen(nat);
487 len += entry_lenlen(nval);
494 /* Flatten an Entry into a buffer. The buffer is filled with just the
495 * strings/bervals of all the entry components. Each field is preceded
496 * by its length, encoded the way ber_put_len works. Every field is NUL
497 * terminated. The entire buffer size is precomputed so that a single
498 * malloc can be performed. The entry size is also recorded,
499 * to aid in entry_decode.
501 static int mdb_entry_encode(Operation *op, MDB_txn *txn, Entry *e, MDB_val *data)
503 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
504 ber_len_t len, dnlen, ndnlen, i;
510 Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n",
511 (long) e->e_id, e->e_dn, 0 );
513 if (is_entry_referral(e))
516 rc = mdb_entry_partsize( mdb, txn, e, &eh );
519 data->mv_size = eh.bv.bv_len;
520 data->mv_data = op->o_tmpalloc(data->mv_size, op->o_tmpmemctx);
521 ptr = (unsigned char *)data->mv_data;
522 mdb_entry_putlen(&ptr, eh.nattrs);
523 mdb_entry_putlen(&ptr, eh.nvals);
524 mdb_entry_putlen(&ptr, e->e_ocflags);
526 for (a=e->e_attrs; a; a=a->a_next) {
527 mdb_entry_putlen(&ptr, mdb->mi_adxs[a->a_desc->ad_index]);
529 for (i=0; a->a_vals[i].bv_val; i++);
530 assert( i == a->a_numvals );
531 mdb_entry_putlen(&ptr, i);
532 for (i=0; a->a_vals[i].bv_val; i++) {
533 mdb_entry_putlen(&ptr, a->a_vals[i].bv_len);
534 AC_MEMCPY(ptr, a->a_vals[i].bv_val,
535 a->a_vals[i].bv_len);
536 ptr += a->a_vals[i].bv_len;
539 if (a->a_nvals != a->a_vals) {
540 mdb_entry_putlen(&ptr, i);
541 for (i=0; a->a_nvals[i].bv_val; i++) {
542 mdb_entry_putlen(&ptr, a->a_nvals[i].bv_len);
543 AC_MEMCPY(ptr, a->a_nvals[i].bv_val,
544 a->a_nvals[i].bv_len);
545 ptr += a->a_nvals[i].bv_len;
549 mdb_entry_putlen(&ptr, 0);
554 Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n",
555 (long) e->e_id, e->e_dn, 0 );
560 /* Retrieve an Entry that was stored using entry_encode above.
562 * Note: everything is stored in a single contiguous block, so
563 * you can not free individual attributes or names from this
564 * structure. Attempting to do so will likely corrupt memory.
567 int mdb_entry_decode(Operation *op, MDB_val *data, Entry **e)
569 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
570 int i, j, nattrs, nvals;
575 AttributeDescription *ad;
576 unsigned char *ptr = (unsigned char *)data->mv_data;
579 Debug( LDAP_DEBUG_TRACE,
580 "=> mdb_entry_decode:\n",
583 nattrs = mdb_entry_getlen(&ptr);
584 nvals = mdb_entry_getlen(&ptr);
586 x->e_ocflags = mdb_entry_getlen(&ptr);
587 x->e_attrs = attrs_alloc( nattrs );
588 x->e_bv.bv_len = nvals * sizeof(struct berval);
589 x->e_bv.bv_val = op->o_tmpalloc(x->e_bv.bv_len, op->o_tmpmemctx);
590 bptr = (BerVarray) x->e_bv.bv_val;
594 while ((i = mdb_entry_getlen(&ptr))) {
595 a->a_desc = mdb->mi_ads[i];
596 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
597 j = mdb_entry_getlen(&ptr);
602 i = mdb_entry_getlen(&ptr);
604 bptr->bv_val = (char *)ptr;
613 j = mdb_entry_getlen(&ptr);
617 i = mdb_entry_getlen(&ptr);
619 bptr->bv_val = (char *)ptr;
628 a->a_nvals = a->a_vals;
630 /* FIXME: This is redundant once a sorted entry is saved into the DB */
631 if ( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
632 rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
633 if ( rc == LDAP_SUCCESS ) {
634 a->a_flags |= SLAP_ATTR_SORTED_VALS;
635 } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
636 /* should never happen */
637 Debug( LDAP_DEBUG_ANY,
638 "mdb_entry_decode: attributeType %s value #%d provided more than once\n",
639 a->a_desc->ad_cname.bv_val, j, 0 );
649 Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n",