]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/id2entry.c
Merge branch 'master' of ssh://git-master.openldap.org/~git/git/openldap
[openldap] / servers / slapd / back-mdb / id2entry.c
1 /* id2entry.c - routines to deal with the id2entry database */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2016 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 #include <ac/errno.h>
22
23 #include "back-mdb.h"
24
25 typedef struct Ecount {
26         ber_len_t len;  /* total entry size */
27         ber_len_t dlen; /* contiguous data size */
28         int nattrs;
29         int nvals;
30         int offset;
31         Attribute *multi;
32 } Ecount;
33
34 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
35         Ecount *eh);
36 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data,
37         Ecount *ec);
38 static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals );
39
40 #define ID2VKSZ (sizeof(ID)+2)
41
42 int
43 mdb_id2v_compare(
44         const MDB_val *usrkey,
45         const MDB_val *curkey
46 )
47 {
48         unsigned short *uv, *cv;
49         ID ui, ci;
50         int rc;
51
52         memcpy(&ui, usrkey->mv_data, sizeof(ID));
53         memcpy(&ci, curkey->mv_data, sizeof(ID));
54         if (ui < ci)
55                 return -1;
56         if (ui > ci)
57                 return 1;
58         uv = usrkey->mv_data;
59         cv = curkey->mv_data;
60         return uv[sizeof(ID)/2] - cv[sizeof(ID)/2];
61 }
62
63 /* Values are stored as
64  * [normalized-value NUL ] original-value NUL 2-byte-len
65  * The trailing 2-byte-len is zero if there is no normalized value.
66  * Otherwise, it is the length of the original-value.
67  */
68 int mdb_mval_put(Operation *op, MDB_cursor *mc, ID id, Attribute *a)
69 {
70         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
71         MDB_val key, data;
72         char *buf;
73         char ivk[ID2VKSZ];
74         unsigned i;
75         unsigned short s;
76         int rc, len;
77
78         memcpy(ivk, &id, sizeof(id));
79         s = mdb->mi_adxs[a->a_desc->ad_index];
80         memcpy(ivk+sizeof(ID), &s, 2);
81         key.mv_data = &ivk;
82         key.mv_size = sizeof(ivk);
83
84         for (i=0; i<a->a_numvals; i++) {
85                 len = a->a_nvals[i].bv_len + 1 + 2;
86                 if (a->a_nvals != a->a_vals)
87                         len += a->a_vals[i].bv_len + 1;
88                 data.mv_size = len;
89                 buf = op->o_tmpalloc( len, op->o_tmpmemctx );
90                 data.mv_data = buf;
91                 memcpy(buf, a->a_nvals[i].bv_val, a->a_nvals[i].bv_len);
92                 buf += a->a_nvals[i].bv_len;
93                 *buf++ = 0;
94                 if (a->a_nvals != a->a_vals) {
95                         s = a->a_vals[i].bv_len;
96                         memcpy(buf, a->a_vals[i].bv_val, a->a_vals[i].bv_len);
97                         buf += a->a_vals[i].bv_len;
98                         *buf++ = 0;
99                         memcpy(buf, &s, 2);
100                 } else {
101                         *buf++ = 0;
102                         *buf++ = 0;
103                 }
104                 rc = mdb_cursor_put(mc, &key, &data, 0);
105                 op->o_tmpfree( data.mv_data, op->o_tmpmemctx );
106                 if (rc)
107                         return rc;
108         }
109         return 0;
110 }
111
112 int mdb_mval_del(Operation *op, MDB_cursor *mc, ID id, Attribute *a)
113 {
114         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
115         MDB_val key, data;
116         char *ptr;
117         char ivk[ID2VKSZ];
118         unsigned i;
119         int rc;
120         unsigned short s;
121
122         memcpy(ivk, &id, sizeof(id));
123         s = mdb->mi_adxs[a->a_desc->ad_index];
124         memcpy(ivk+sizeof(ID), &s, 2);
125         key.mv_data = &ivk;
126         key.mv_size = sizeof(ivk);
127
128         if (a->a_numvals) {
129                 for (i=0; i<a->a_numvals; i++) {
130                         data.mv_data = a->a_nvals[i].bv_val;
131                         data.mv_size = a->a_nvals[i].bv_len+1;
132                         rc = mdb_cursor_get(mc, &key, &data, MDB_GET_BOTH_RANGE);
133                         if (rc)
134                                 return rc;
135                         rc = mdb_cursor_del(mc, 0);
136                         if (rc)
137                                 return rc;
138                 }
139         } else {
140                 rc = mdb_cursor_get(mc, &key, &data, MDB_SET);
141                 if (rc)
142                         return rc;
143                 rc = mdb_cursor_del(mc, MDB_NODUPDATA);
144         }
145         return rc;
146 }
147
148 static int mdb_mval_get(Operation *op, MDB_cursor *mc, ID id, Attribute *a, int have_nvals)
149 {
150         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
151         MDB_val key, data;
152         char *ptr;
153         char ivk[ID2VKSZ];
154         unsigned i;
155         int rc;
156         unsigned short s;
157
158         memcpy(ivk, &id, sizeof(id));
159         s = mdb->mi_adxs[a->a_desc->ad_index];
160         memcpy(ivk+sizeof(ID), &s, 2);
161         key.mv_data = &ivk;
162         key.mv_size = sizeof(ivk);
163
164         if (have_nvals)
165                 a->a_nvals = a->a_vals + a->a_numvals + 1;
166         else
167                 a->a_nvals = a->a_vals;
168         for (i=0; i<a->a_numvals; i++) {
169                 if (!i)
170                         rc = mdb_cursor_get(mc, &key, &data, MDB_SET);
171                 else
172                         rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT_DUP);
173                 if (rc)
174                         return rc;
175                 ptr = (char*)data.mv_data + data.mv_size - 2;
176                 memcpy(&s, ptr, 2);
177                 if (have_nvals) {
178                         a->a_nvals[i].bv_val = data.mv_data;
179                         a->a_vals[i].bv_len = s;
180                         a->a_vals[i].bv_val = ptr - a->a_vals[i].bv_len - 1;
181                         a->a_nvals[i].bv_len = a->a_vals[i].bv_val - a->a_nvals[i].bv_val - 1;
182                 } else {
183                         assert(!s);
184                         a->a_vals[i].bv_val = data.mv_data;
185                         a->a_vals[i].bv_len = data.mv_size - 3;
186                 }
187         }
188         BER_BVZERO(&a->a_vals[i]);
189         if (have_nvals) {
190                 BER_BVZERO(&a->a_nvals[i]);
191         }
192         return 0;
193 }
194
195 #define ADD_FLAGS       (MDB_NOOVERWRITE|MDB_APPEND)
196
197 static int mdb_id2entry_put(
198         Operation *op,
199         MDB_txn *txn,
200         MDB_cursor *mc,
201         Entry *e,
202         int flag )
203 {
204         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
205         Ecount ec;
206         MDB_val key, data;
207         int rc, adding = flag;
208
209         /* We only store rdns, and they go in the dn2id database. */
210
211         key.mv_data = &e->e_id;
212         key.mv_size = sizeof(ID);
213
214         rc = mdb_entry_partsize( mdb, txn, e, &ec );
215         if (rc)
216                 return LDAP_OTHER;
217
218         flag |= MDB_RESERVE;
219
220         if (e->e_id < mdb->mi_nextid)
221                 flag &= ~MDB_APPEND;
222
223         if (mdb->mi_maxentrysize && ec.len > mdb->mi_maxentrysize)
224                 return LDAP_ADMINLIMIT_EXCEEDED;
225
226 again:
227         data.mv_size = ec.dlen;
228         if ( mc )
229                 rc = mdb_cursor_put( mc, &key, &data, flag );
230         else
231                 rc = mdb_put( txn, mdb->mi_id2entry, &key, &data, flag );
232         if (rc == MDB_SUCCESS) {
233                 rc = mdb_entry_encode( op, e, &data, &ec );
234                 if( rc != LDAP_SUCCESS )
235                         return rc;
236                 /* Handle adds of large multi-valued attrs here.
237                  * Modifies handle them directly.
238                  */
239                 if (adding && ec.multi) {
240                         MDB_cursor *mvc;
241                         Attribute *a;
242                         rc = mdb_cursor_open( txn, mdb->mi_dbis[MDB_ID2VAL], &mvc );
243                         if( rc )
244                                 return rc;
245                         for ( a = ec.multi; a; a=a->a_next ) {
246                                 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI))
247                                         continue;
248                                 rc = mdb_mval_put( op, mvc, e->e_id, a );
249                                 if( rc != LDAP_SUCCESS )
250                                         break;
251                         }
252                         mdb_cursor_close( mvc );
253                         if ( rc )
254                                 return rc;
255                 }
256         }
257         if (rc) {
258                 /* Was there a hole from slapadd? */
259                 if ( (flag & MDB_NOOVERWRITE) && data.mv_size == 0 ) {
260                         flag &= ~ADD_FLAGS;
261                         goto again;
262                 }
263                 Debug( LDAP_DEBUG_ANY,
264                         "mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n",
265                         mdb_strerror(rc), rc,
266                         e->e_nname.bv_val );
267                 if ( rc != MDB_KEYEXIST )
268                         rc = LDAP_OTHER;
269         }
270         return rc;
271 }
272
273 /*
274  * This routine adds (or updates) an entry on disk.
275  */
276 int mdb_id2entry_add(
277         Operation *op,
278         MDB_txn *txn,
279         MDB_cursor *mc,
280         Entry *e )
281 {
282         return mdb_id2entry_put(op, txn, mc, e, ADD_FLAGS);
283 }
284
285 int mdb_id2entry_update(
286         Operation *op,
287         MDB_txn *txn,
288         MDB_cursor *mc,
289         Entry *e )
290 {
291         return mdb_id2entry_put(op, txn, mc, e, 0);
292 }
293
294 int mdb_id2edata(
295         Operation *op,
296         MDB_cursor *mc,
297         ID id,
298         MDB_val *data )
299 {
300         MDB_val key;
301         int rc;
302
303         key.mv_data = &id;
304         key.mv_size = sizeof(ID);
305
306         /* fetch it */
307         rc = mdb_cursor_get( mc, &key, data, MDB_SET );
308         /* stubs from missing parents - DB is actually invalid */
309         if ( rc == MDB_SUCCESS && !data->mv_size )
310                 rc = MDB_NOTFOUND;
311         return rc;
312 }
313
314 int mdb_id2entry(
315         Operation *op,
316         MDB_cursor *mc,
317         ID id,
318         Entry **e )
319 {
320         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
321         MDB_val key, data;
322         int rc = 0;
323
324         *e = NULL;
325
326         key.mv_data = &id;
327         key.mv_size = sizeof(ID);
328
329         /* fetch it */
330         rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
331         if ( rc == MDB_NOTFOUND ) {
332                 /* Looking for root entry on an empty-dn suffix? */
333                 if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) {
334                         struct berval gluebv = BER_BVC("glue");
335                         Entry *r = mdb_entry_alloc(op, 2, 4);
336                         Attribute *a = r->e_attrs;
337                         struct berval *bptr;
338
339                         r->e_id = 0;
340                         r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
341                         bptr = a->a_vals;
342                         a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
343                         a->a_desc = slap_schema.si_ad_objectClass;
344                         a->a_nvals = a->a_vals;
345                         a->a_numvals = 1;
346                         *bptr++ = gluebv;
347                         BER_BVZERO(bptr);
348                         bptr++;
349                         a->a_next = a+1;
350                         a = a->a_next;
351                         a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
352                         a->a_desc = slap_schema.si_ad_structuralObjectClass;
353                         a->a_vals = bptr;
354                         a->a_nvals = a->a_vals;
355                         a->a_numvals = 1;
356                         *bptr++ = gluebv;
357                         BER_BVZERO(bptr);
358                         a->a_next = NULL;
359                         *e = r;
360                         return MDB_SUCCESS;
361                 }
362         }
363         /* stubs from missing parents - DB is actually invalid */
364         if ( rc == MDB_SUCCESS && !data.mv_size )
365                 rc = MDB_NOTFOUND;
366         if ( rc ) return rc;
367
368         rc = mdb_entry_decode( op, mdb_cursor_txn( mc ), &data, id, e );
369         if ( rc ) return rc;
370
371         (*e)->e_id = id;
372         (*e)->e_name.bv_val = NULL;
373         (*e)->e_nname.bv_val = NULL;
374
375         return rc;
376 }
377
378 int mdb_id2entry_delete(
379         BackendDB *be,
380         MDB_txn *tid,
381         Entry *e )
382 {
383         struct mdb_info *mdb = (struct mdb_info *) be->be_private;
384         MDB_dbi dbi = mdb->mi_id2entry;
385         MDB_val key;
386         MDB_cursor *mvc;
387         int rc;
388
389         key.mv_data = &e->e_id;
390         key.mv_size = sizeof(ID);
391
392         /* delete from database */
393         rc = mdb_del( tid, dbi, &key, NULL );
394         if (rc)
395                 return rc;
396         rc = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
397         if (rc)
398                 return rc;
399
400         rc = mdb_cursor_get( mvc, &key, NULL, MDB_SET_RANGE );
401         if (rc) {
402                 if (rc == MDB_NOTFOUND)
403                         rc = MDB_SUCCESS;
404                 return rc;
405         }
406         while (*(ID *)key.mv_data == e->e_id ) {
407                 rc = mdb_cursor_del( mvc, MDB_NODUPDATA );
408                 if (rc)
409                         return rc;
410                 mdb_cursor_get( mvc, &key, NULL, MDB_GET_CURRENT );
411         }
412         return rc;
413 }
414
415 static Entry * mdb_entry_alloc(
416         Operation *op,
417         int nattrs,
418         int nvals )
419 {
420         Entry *e = op->o_tmpalloc( sizeof(Entry) +
421                 nattrs * sizeof(Attribute) +
422                 nvals * sizeof(struct berval), op->o_tmpmemctx );
423         BER_BVZERO(&e->e_bv);
424         e->e_private = e;
425         if (nattrs) {
426                 e->e_attrs = (Attribute *)(e+1);
427                 e->e_attrs->a_vals = (struct berval *)(e->e_attrs+nattrs);
428         } else {
429                 e->e_attrs = NULL;
430         }
431
432         return e;
433 }
434
435 int mdb_entry_return(
436         Operation *op,
437         Entry *e
438 )
439 {
440         if ( !e )
441                 return 0;
442         if ( e->e_private ) {
443                 if ( op->o_hdr && op->o_tmpmfuncs ) {
444                         op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
445                         op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
446                         op->o_tmpfree( e, op->o_tmpmemctx );
447                 } else {
448                         ch_free( e->e_nname.bv_val );
449                         ch_free( e->e_name.bv_val );
450                         ch_free( e );
451                 }
452         } else {
453                 entry_free( e );
454         }
455         return 0;
456 }
457
458 int mdb_entry_release(
459         Operation *op,
460         Entry *e,
461         int rw )
462 {
463         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
464         struct mdb_op_info *moi = NULL;
465         int rc;
466  
467         /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
468                         SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
469  
470         int release = 1;
471         if ( slapMode & SLAP_SERVER_MODE ) {
472                 OpExtra *oex;
473                 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
474                         release = 0;
475                         if ( oex->oe_key == mdb ) {
476                                 mdb_entry_return( op, e );
477                                 moi = (mdb_op_info *)oex;
478                                 /* If it was setup by entry_get we should probably free it */
479                                 if (( moi->moi_flag & (MOI_FREEIT|MOI_KEEPER)) == MOI_FREEIT ) {
480                                         moi->moi_ref--;
481                                         if ( moi->moi_ref < 1 ) {
482                                                 mdb_txn_reset( moi->moi_txn );
483                                                 moi->moi_ref = 0;
484                                                 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
485                                                 op->o_tmpfree( moi, op->o_tmpmemctx );
486                                         }
487                                 }
488                                 break;
489                         }
490                 }
491         }
492
493         if (release)
494                 mdb_entry_return( op, e );
495  
496         return 0;
497 }
498
499 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
500  */
501 int mdb_entry_get(
502         Operation *op,
503         struct berval *ndn,
504         ObjectClass *oc,
505         AttributeDescription *at,
506         int rw,
507         Entry **ent )
508 {
509         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
510         struct mdb_op_info *moi = NULL;
511         MDB_txn *txn = NULL;
512         Entry *e = NULL;
513         int     rc;
514         const char *at_name = at ? at->ad_cname.bv_val : "(null)";
515
516         Debug( LDAP_DEBUG_ARGS,
517                 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); 
518         Debug( LDAP_DEBUG_ARGS,
519                 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
520                 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
521
522         rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
523         if ( rc )
524                 return LDAP_OTHER;
525         txn = moi->moi_txn;
526
527         /* can we find entry */
528         rc = mdb_dn2entry( op, txn, NULL, ndn, &e, NULL, 0 );
529         switch( rc ) {
530         case MDB_NOTFOUND:
531         case 0:
532                 break;
533         default:
534                 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
535         }
536         if (e == NULL) {
537                 Debug( LDAP_DEBUG_ACL,
538                         "=> mdb_entry_get: cannot find entry: \"%s\"\n",
539                                 ndn->bv_val, 0, 0 ); 
540                 rc = LDAP_NO_SUCH_OBJECT;
541                 goto return_results;
542         }
543         
544         Debug( LDAP_DEBUG_ACL,
545                 "=> mdb_entry_get: found entry: \"%s\"\n",
546                 ndn->bv_val, 0, 0 ); 
547
548         if ( oc && !is_entry_objectclass( e, oc, 0 )) {
549                 Debug( LDAP_DEBUG_ACL,
550                         "<= mdb_entry_get: failed to find objectClass %s\n",
551                         oc->soc_cname.bv_val, 0, 0 ); 
552                 rc = LDAP_NO_SUCH_ATTRIBUTE;
553                 goto return_results;
554         }
555
556         /* NOTE: attr_find() or attrs_find()? */
557         if ( at && attr_find( e->e_attrs, at ) == NULL ) {
558                 Debug( LDAP_DEBUG_ACL,
559                         "<= mdb_entry_get: failed to find attribute %s\n",
560                         at->ad_cname.bv_val, 0, 0 ); 
561                 rc = LDAP_NO_SUCH_ATTRIBUTE;
562                 goto return_results;
563         }
564
565 return_results:
566         if( rc != LDAP_SUCCESS ) {
567                 /* free entry */
568                 mdb_entry_release( op, e, rw );
569         } else {
570                 *ent = e;
571         }
572
573         Debug( LDAP_DEBUG_TRACE,
574                 "mdb_entry_get: rc=%d\n",
575                 rc, 0, 0 ); 
576         return(rc);
577 }
578
579 static void
580 mdb_reader_free( void *key, void *data )
581 {
582         MDB_txn *txn = data;
583
584         if ( txn ) mdb_txn_abort( txn );
585 }
586
587 /* free up any keys used by the main thread */
588 void
589 mdb_reader_flush( MDB_env *env )
590 {
591         void *data;
592         void *ctx = ldap_pvt_thread_pool_context();
593
594         if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
595                 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
596                 mdb_reader_free( env, data );
597         }
598 }
599
600 extern MDB_txn *mdb_tool_txn;
601
602 int
603 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
604 {
605         int rc, renew = 0;
606         void *data;
607         void *ctx;
608         mdb_op_info *moi = NULL;
609         OpExtra *oex;
610
611         assert( op != NULL );
612
613         if ( !mdb || !moip ) return -1;
614
615         /* If no op was provided, try to find the ctx anyway... */
616         if ( op ) {
617                 ctx = op->o_threadctx;
618         } else {
619                 ctx = ldap_pvt_thread_pool_context();
620         }
621
622         if ( op ) {
623                 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
624                         if ( oex->oe_key == mdb ) break;
625                 }
626                 moi = (mdb_op_info *)oex;
627         }
628
629         if ( !moi ) {
630                 moi = *moip;
631
632                 if ( !moi ) {
633                         if ( op ) {
634                                 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
635                         } else {
636                                 moi = ch_malloc(sizeof(mdb_op_info));
637                         }
638                         moi->moi_flag = MOI_FREEIT;
639                         *moip = moi;
640                 }
641                 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
642                 moi->moi_oe.oe_key = mdb;
643                 moi->moi_ref = 0;
644                 moi->moi_txn = NULL;
645         }
646
647         if ( !rdonly ) {
648                 /* This op started as a reader, but now wants to write. */
649                 if ( moi->moi_flag & MOI_READER ) {
650                         moi = *moip;
651                         LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
652                 } else {
653                 /* This op is continuing an existing write txn */
654                         *moip = moi;
655                 }
656                 moi->moi_ref++;
657                 if ( !moi->moi_txn ) {
658                         if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) {
659                                 moi->moi_txn = mdb_tool_txn;
660                         } else {
661                                 int flag = 0;
662                                 if ( get_lazyCommit( op ))
663                                         flag |= MDB_NOMETASYNC;
664                                 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, flag, &moi->moi_txn );
665                                 if (rc) {
666                                         Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
667                                                 mdb_strerror(rc), rc, 0 );
668                                 }
669                                 return rc;
670                         }
671                 }
672                 return 0;
673         }
674
675         /* OK, this is a reader */
676         if ( !moi->moi_txn ) {
677                 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) {
678                         moi->moi_txn = mdb_tool_txn;
679                         goto ok;
680                 }
681                 if ( !ctx ) {
682                         /* Shouldn't happen unless we're single-threaded */
683                         rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
684                         if (rc) {
685                                 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
686                                         mdb_strerror(rc), rc, 0 );
687                         }
688                         return rc;
689                 }
690                 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
691                         rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
692                         if (rc) {
693                                 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
694                                         mdb_strerror(rc), rc, 0 );
695                                 return rc;
696                         }
697                         data = moi->moi_txn;
698                         if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
699                                 data, mdb_reader_free, NULL, NULL ) ) ) {
700                                 mdb_txn_abort( moi->moi_txn );
701                                 moi->moi_txn = NULL;
702                                 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
703                                         rc, 0, 0 );
704                                 return rc;
705                         }
706                 } else {
707                         moi->moi_txn = data;
708                         renew = 1;
709                 }
710                 moi->moi_flag |= MOI_READER;
711         }
712 ok:
713         if ( moi->moi_ref < 1 ) {
714                 moi->moi_ref = 0;
715         }
716         if ( renew ) {
717                 rc = mdb_txn_renew( moi->moi_txn );
718                 assert(!rc);
719         }
720         moi->moi_ref++;
721         if ( *moip != moi )
722                 *moip = moi;
723
724         return 0;
725 }
726
727 #ifdef LDAP_X_TXN
728 int mdb_txn( Operation *op, int txnop, OpExtra **ptr )
729 {
730         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
731         mdb_op_info **moip = (mdb_op_info **)ptr, *moi = *moip;
732         int rc;
733
734         switch( txnop ) {
735         case SLAP_TXN_BEGIN:
736                 rc = mdb_opinfo_get( op, mdb, 0, moip );
737                 if ( !rc ) {
738                         moi = *moip;
739                         moi->moi_flag |= MOI_KEEPER;
740                 }
741                 return rc;
742         case SLAP_TXN_COMMIT:
743                 rc = mdb_txn_commit( moi->moi_txn );
744                 if ( rc )
745                         mdb->mi_numads = 0;
746                 op->o_tmpfree( moi, op->o_tmpmemctx );
747                 return rc;
748         case SLAP_TXN_ABORT:
749                 mdb->mi_numads = 0;
750                 mdb_txn_abort( moi->moi_txn );
751                 op->o_tmpfree( moi, op->o_tmpmemctx );
752                 return 0;
753         }
754         return LDAP_OTHER;
755 }
756 #endif
757
758 /* Count up the sizes of the components of an entry */
759 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
760         Ecount *eh)
761 {
762         ber_len_t len, dlen;
763         int i, nat = 0, nval = 0, nnval = 0, doff = 0;
764         Attribute *a;
765
766         eh->multi = NULL;
767         len = 4*sizeof(int);    /* nattrs, nvals, ocflags, offset */
768         dlen = len;
769         for (a=e->e_attrs; a; a=a->a_next) {
770                 /* For AttributeDesc, we only store the attr index */
771                 nat++;
772                 if (a->a_desc->ad_index >= MDB_MAXADS) {
773                         Debug( LDAP_DEBUG_ANY, "mdb_entry_partsize: too many AttributeDescriptions used\n",
774                                 0, 0, 0 );
775                         return LDAP_OTHER;
776                 }
777                 if (!mdb->mi_adxs[a->a_desc->ad_index]) {
778                         int rc = mdb_ad_get(mdb, txn, a->a_desc);
779                         if (rc)
780                                 return rc;
781                 }
782                 len += 2*sizeof(int);   /* AD index, numvals */
783                 dlen += 2*sizeof(int);
784                 nval += a->a_numvals + 1;       /* empty berval at end */
785                 if (a->a_numvals > mdb->mi_multi_hi)
786                         a->a_flags |= SLAP_ATTR_BIG_MULTI;
787                 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
788                         doff += a->a_numvals;
789                 for (i=0; i<a->a_numvals; i++) {
790                         int alen = a->a_vals[i].bv_len + 1 + sizeof(int);       /* len */
791                         len += alen;
792                         if (a->a_flags & SLAP_ATTR_BIG_MULTI) {
793                                 if (!eh->multi)
794                                         eh->multi = a;
795                         } else {
796                                 dlen += alen;
797                         }
798                 }
799                 if (a->a_nvals != a->a_vals) {
800                         nval += a->a_numvals + 1;
801                         nnval++;
802                         if (a->a_flags & SLAP_ATTR_BIG_MULTI)
803                                 doff += a->a_numvals;
804                         for (i=0; i<a->a_numvals; i++) {
805                                 int alen = a->a_nvals[i].bv_len + 1 + sizeof(int);
806                                 len += alen;
807                                 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI))
808                                         dlen += alen;
809                         }
810                 }
811         }
812         /* padding */
813         dlen = (dlen + sizeof(ID)-1) & ~(sizeof(ID)-1);
814         eh->len = len;
815         eh->dlen = dlen;
816         eh->nattrs = nat;
817         eh->nvals = nval;
818         eh->offset = nat + nval - nnval - doff;
819         return 0;
820 }
821
822 /* Flag bits for an encoded attribute */
823 #define MDB_AT_SORTED   (1<<(sizeof(unsigned int)*CHAR_BIT-1))
824         /* the values are in sorted order */
825 #define MDB_AT_MULTI    (1<<(sizeof(unsigned int)*CHAR_BIT-2))
826         /* the values of this multi-valued attr are stored separately */
827
828 #define MDB_AT_NVALS    (1<<(sizeof(unsigned int)*CHAR_BIT-1))
829         /* this attribute has normalized values */
830
831 /* Flatten an Entry into a buffer. The buffer starts with the count of the
832  * number of attributes in the entry, the total number of values in the
833  * entry, and the e_ocflags. It then contains a list of integers for each
834  * attribute. For each attribute the first integer gives the index of the
835  * matching AttributeDescription, followed by the number of values in the
836  * attribute. If the MDB_AT_SORTED bit of the attr index is set, the
837  * attribute's values are already sorted. If the MDB_AT_MULTI bit of the
838  * attr index is set, the values are stored separately.
839  *
840  * If the MDB_AT_NVALS bit of numvals is set, the attribute also has
841  * normalized values present. (Note - a_numvals is an unsigned int, so this
842  * means it's possible to receive an attribute that we can't encode due
843  * to size overflow. In practice, this should not be an issue.)
844  *
845  * Then the length of each value is listed. If there are normalized values,
846  * their lengths come next. This continues for each attribute. After all
847  * of the lengths for the last attribute, the actual values are copied,
848  * with a NUL terminator after each value.
849  * The buffer is padded to the sizeof(ID). The entire buffer size is
850  * precomputed so that a single malloc can be performed.
851  */
852 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh)
853 {
854         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
855         ber_len_t len, i;
856         int rc;
857         Attribute *a;
858         unsigned char *ptr;
859         unsigned int *lp, l;
860
861         Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n",
862                 (long) e->e_id, e->e_dn, 0 );
863
864         /* make sure e->e_ocflags is set */
865         if (is_entry_referral(e))
866                 ;       /* empty */
867
868         lp = (unsigned int *)data->mv_data;
869         *lp++ = eh->nattrs;
870         *lp++ = eh->nvals;
871         *lp++ = (unsigned int)e->e_ocflags;
872         *lp++ = eh->offset;
873         ptr = (unsigned char *)(lp + eh->offset);
874
875         for (a=e->e_attrs; a; a=a->a_next) {
876                 if (!a->a_desc->ad_index)
877                         return LDAP_UNDEFINED_TYPE;
878                 l = mdb->mi_adxs[a->a_desc->ad_index];
879                 if (a->a_flags & SLAP_ATTR_SORTED_VALS)
880                         l |= MDB_AT_SORTED;
881                 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
882                         l |= MDB_AT_MULTI;
883                 *lp++ = l;
884                 l = a->a_numvals;
885                 if (a->a_nvals != a->a_vals)
886                         l |= MDB_AT_NVALS;
887                 *lp++ = l;
888                 if (a->a_flags & SLAP_ATTR_BIG_MULTI) {
889                         continue;
890                 } else {
891                         if (a->a_vals) {
892                                 for (i=0; a->a_vals[i].bv_val; i++);
893                                 assert( i == a->a_numvals );
894                                 for (i=0; i<a->a_numvals; i++) {
895                                         *lp++ = a->a_vals[i].bv_len;
896                                         memcpy(ptr, a->a_vals[i].bv_val,
897                                                 a->a_vals[i].bv_len);
898                                         ptr += a->a_vals[i].bv_len;
899                                         *ptr++ = '\0';
900                                 }
901                                 if (a->a_nvals != a->a_vals) {
902                                         for (i=0; i<a->a_numvals; i++) {
903                                                 *lp++ = a->a_nvals[i].bv_len;
904                                                 memcpy(ptr, a->a_nvals[i].bv_val,
905                                                         a->a_nvals[i].bv_len);
906                                                 ptr += a->a_nvals[i].bv_len;
907                                                 *ptr++ = '\0';
908                                         }
909                                 }
910                         }
911                 }
912         }
913
914         Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n",
915                 (long) e->e_id, e->e_dn, 0 );
916
917         return 0;
918 }
919
920 /* Retrieve an Entry that was stored using entry_encode above.
921  *
922  * Note: everything is stored in a single contiguous block, so
923  * you can not free individual attributes or names from this
924  * structure. Attempting to do so will likely corrupt memory.
925  */
926
927 int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, ID id, Entry **e)
928 {
929         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
930         int i, j, nattrs, nvals;
931         int rc;
932         Attribute *a;
933         Entry *x;
934         const char *text;
935         AttributeDescription *ad;
936         unsigned int *lp = (unsigned int *)data->mv_data;
937         unsigned char *ptr;
938         BerVarray bptr;
939         MDB_cursor *mvc = NULL;
940
941         Debug( LDAP_DEBUG_TRACE,
942                 "=> mdb_entry_decode:\n",
943                 0, 0, 0 );
944
945         nattrs = *lp++;
946         nvals = *lp++;
947         x = mdb_entry_alloc(op, nattrs, nvals);
948         x->e_ocflags = *lp++;
949         if (!nvals) {
950                 goto done;
951         }
952         a = x->e_attrs;
953         bptr = a->a_vals;
954         i = *lp++;
955         ptr = (unsigned char *)(lp + i);
956
957         for (;nattrs>0; nattrs--) {
958                 int have_nval = 0, multi = 0;
959                 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
960                 i = *lp++;
961                 if (i & MDB_AT_SORTED) {
962                         i ^= MDB_AT_SORTED;
963                         a->a_flags |= SLAP_ATTR_SORTED_VALS;
964                 }
965                 if (i & MDB_AT_MULTI) {
966                         i ^= MDB_AT_MULTI;
967                         a->a_flags |= SLAP_ATTR_BIG_MULTI;
968                         multi = 1;
969                 }
970                 if (i > mdb->mi_numads) {
971                         rc = mdb_ad_read(mdb, txn);
972                         if (rc)
973                                 goto leave;
974                         if (i > mdb->mi_numads) {
975                                 Debug( LDAP_DEBUG_ANY,
976                                         "mdb_entry_decode: attribute index %d not recognized\n",
977                                         i, 0, 0 );
978                                 rc = LDAP_OTHER;
979                                 goto leave;
980                         }
981                 }
982                 a->a_desc = mdb->mi_ads[i];
983                 a->a_numvals = *lp++;
984                 if (a->a_numvals & MDB_AT_NVALS) {
985                         a->a_numvals ^= MDB_AT_NVALS;
986                         have_nval = 1;
987                 }
988                 a->a_vals = bptr;
989                 if (multi) {
990                         if (!mvc) {
991                                 rc = mdb_cursor_open(txn, mdb->mi_dbis[MDB_ID2VAL], &mvc);
992                                 if (rc)
993                                         goto leave;
994                         }
995                         mdb_mval_get(op, mvc, id, a, have_nval);
996                         bptr += a->a_numvals + 1;
997                         if (have_nval)
998                                 bptr += a->a_numvals + 1;
999                 } else {
1000                         for (i=0; i<a->a_numvals; i++) {
1001                                 bptr->bv_len = *lp++;
1002                                 bptr->bv_val = (char *)ptr;
1003                                 ptr += bptr->bv_len+1;
1004                                 bptr++;
1005                         }
1006                         bptr->bv_val = NULL;
1007                         bptr->bv_len = 0;
1008                         bptr++;
1009
1010                         if (have_nval) {
1011                                 a->a_nvals = bptr;
1012                                 for (i=0; i<a->a_numvals; i++) {
1013                                         bptr->bv_len = *lp++;
1014                                         bptr->bv_val = (char *)ptr;
1015                                         ptr += bptr->bv_len+1;
1016                                         bptr++;
1017                                 }
1018                                 bptr->bv_val = NULL;
1019                                 bptr->bv_len = 0;
1020                                 bptr++;
1021                         } else {
1022                                 a->a_nvals = a->a_vals;
1023                         }
1024                 }
1025
1026                 /* FIXME: This is redundant once a sorted entry is saved into the DB */
1027                 if (( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
1028                         && !(a->a_flags & SLAP_ATTR_SORTED_VALS)) {
1029                         rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
1030                         if ( rc == LDAP_SUCCESS ) {
1031                                 a->a_flags |= SLAP_ATTR_SORTED_VALS;
1032                         } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
1033                                 /* should never happen */
1034                                 Debug( LDAP_DEBUG_ANY,
1035                                         "mdb_entry_decode: attributeType %s value #%d provided more than once\n",
1036                                         a->a_desc->ad_cname.bv_val, j, 0 );
1037                                 goto leave;
1038                         }
1039                 }
1040                 a->a_next = a+1;
1041                 a = a->a_next;
1042         }
1043         a[-1].a_next = NULL;
1044 done:
1045         Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n",
1046                 0, 0, 0 );
1047         *e = x;
1048         rc = 0;
1049
1050 leave:
1051         if (mvc)
1052                 mdb_cursor_close(mvc);
1053         return rc;
1054 }