]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/id2entry.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[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-2017 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                 rc = mdb_cursor_get( mvc, &key, NULL, MDB_GET_CURRENT );
411                 if (rc) {
412                         if (rc == MDB_NOTFOUND)
413                                 rc = MDB_SUCCESS;
414                         break;
415                 }
416         }
417         return rc;
418 }
419
420 static Entry * mdb_entry_alloc(
421         Operation *op,
422         int nattrs,
423         int nvals )
424 {
425         Entry *e = op->o_tmpalloc( sizeof(Entry) +
426                 nattrs * sizeof(Attribute) +
427                 nvals * sizeof(struct berval), op->o_tmpmemctx );
428         BER_BVZERO(&e->e_bv);
429         e->e_private = e;
430         if (nattrs) {
431                 e->e_attrs = (Attribute *)(e+1);
432                 e->e_attrs->a_vals = (struct berval *)(e->e_attrs+nattrs);
433         } else {
434                 e->e_attrs = NULL;
435         }
436
437         return e;
438 }
439
440 int mdb_entry_return(
441         Operation *op,
442         Entry *e
443 )
444 {
445         if ( !e )
446                 return 0;
447         if ( e->e_private ) {
448                 if ( op->o_hdr && op->o_tmpmfuncs ) {
449                         op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
450                         op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
451                         op->o_tmpfree( e, op->o_tmpmemctx );
452                 } else {
453                         ch_free( e->e_nname.bv_val );
454                         ch_free( e->e_name.bv_val );
455                         ch_free( e );
456                 }
457         } else {
458                 entry_free( e );
459         }
460         return 0;
461 }
462
463 int mdb_entry_release(
464         Operation *op,
465         Entry *e,
466         int rw )
467 {
468         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
469         struct mdb_op_info *moi = NULL;
470         int rc;
471  
472         /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
473                         SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
474  
475         int release = 1;
476         if ( slapMode & SLAP_SERVER_MODE ) {
477                 OpExtra *oex;
478                 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
479                         release = 0;
480                         if ( oex->oe_key == mdb ) {
481                                 mdb_entry_return( op, e );
482                                 moi = (mdb_op_info *)oex;
483                                 /* If it was setup by entry_get we should probably free it */
484                                 if (( moi->moi_flag & (MOI_FREEIT|MOI_KEEPER)) == MOI_FREEIT ) {
485                                         moi->moi_ref--;
486                                         if ( moi->moi_ref < 1 ) {
487                                                 mdb_txn_reset( moi->moi_txn );
488                                                 moi->moi_ref = 0;
489                                                 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
490                                                 op->o_tmpfree( moi, op->o_tmpmemctx );
491                                         }
492                                 }
493                                 break;
494                         }
495                 }
496         }
497
498         if (release)
499                 mdb_entry_return( op, e );
500  
501         return 0;
502 }
503
504 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
505  */
506 int mdb_entry_get(
507         Operation *op,
508         struct berval *ndn,
509         ObjectClass *oc,
510         AttributeDescription *at,
511         int rw,
512         Entry **ent )
513 {
514         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
515         struct mdb_op_info *moi = NULL;
516         MDB_txn *txn = NULL;
517         Entry *e = NULL;
518         int     rc;
519         const char *at_name = at ? at->ad_cname.bv_val : "(null)";
520
521         Debug( LDAP_DEBUG_ARGS,
522                 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); 
523         Debug( LDAP_DEBUG_ARGS,
524                 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
525                 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
526
527         rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
528         if ( rc )
529                 return LDAP_OTHER;
530         txn = moi->moi_txn;
531
532         /* can we find entry */
533         rc = mdb_dn2entry( op, txn, NULL, ndn, &e, NULL, 0 );
534         switch( rc ) {
535         case MDB_NOTFOUND:
536         case 0:
537                 break;
538         default:
539                 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
540         }
541         if (e == NULL) {
542                 Debug( LDAP_DEBUG_ACL,
543                         "=> mdb_entry_get: cannot find entry: \"%s\"\n",
544                                 ndn->bv_val, 0, 0 ); 
545                 rc = LDAP_NO_SUCH_OBJECT;
546                 goto return_results;
547         }
548         
549         Debug( LDAP_DEBUG_ACL,
550                 "=> mdb_entry_get: found entry: \"%s\"\n",
551                 ndn->bv_val, 0, 0 ); 
552
553         if ( oc && !is_entry_objectclass( e, oc, 0 )) {
554                 Debug( LDAP_DEBUG_ACL,
555                         "<= mdb_entry_get: failed to find objectClass %s\n",
556                         oc->soc_cname.bv_val, 0, 0 ); 
557                 rc = LDAP_NO_SUCH_ATTRIBUTE;
558                 goto return_results;
559         }
560
561         /* NOTE: attr_find() or attrs_find()? */
562         if ( at && attr_find( e->e_attrs, at ) == NULL ) {
563                 Debug( LDAP_DEBUG_ACL,
564                         "<= mdb_entry_get: failed to find attribute %s\n",
565                         at->ad_cname.bv_val, 0, 0 ); 
566                 rc = LDAP_NO_SUCH_ATTRIBUTE;
567                 goto return_results;
568         }
569
570 return_results:
571         if( rc != LDAP_SUCCESS ) {
572                 /* free entry */
573                 mdb_entry_release( op, e, rw );
574         } else {
575                 *ent = e;
576         }
577
578         Debug( LDAP_DEBUG_TRACE,
579                 "mdb_entry_get: rc=%d\n",
580                 rc, 0, 0 ); 
581         return(rc);
582 }
583
584 static void
585 mdb_reader_free( void *key, void *data )
586 {
587         MDB_txn *txn = data;
588
589         if ( txn ) mdb_txn_abort( txn );
590 }
591
592 /* free up any keys used by the main thread */
593 void
594 mdb_reader_flush( MDB_env *env )
595 {
596         void *data;
597         void *ctx = ldap_pvt_thread_pool_context();
598
599         if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
600                 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
601                 mdb_reader_free( env, data );
602         }
603 }
604
605 extern MDB_txn *mdb_tool_txn;
606
607 int
608 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
609 {
610         int rc, renew = 0;
611         void *data;
612         void *ctx;
613         mdb_op_info *moi = NULL;
614         OpExtra *oex;
615
616         assert( op != NULL );
617
618         if ( !mdb || !moip ) return -1;
619
620         /* If no op was provided, try to find the ctx anyway... */
621         if ( op ) {
622                 ctx = op->o_threadctx;
623         } else {
624                 ctx = ldap_pvt_thread_pool_context();
625         }
626
627         if ( op ) {
628                 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
629                         if ( oex->oe_key == mdb ) break;
630                 }
631                 moi = (mdb_op_info *)oex;
632         }
633
634         if ( !moi ) {
635                 moi = *moip;
636
637                 if ( !moi ) {
638                         if ( op ) {
639                                 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
640                         } else {
641                                 moi = ch_malloc(sizeof(mdb_op_info));
642                         }
643                         moi->moi_flag = MOI_FREEIT;
644                         *moip = moi;
645                 }
646                 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
647                 moi->moi_oe.oe_key = mdb;
648                 moi->moi_ref = 0;
649                 moi->moi_txn = NULL;
650         }
651
652         if ( !rdonly ) {
653                 /* This op started as a reader, but now wants to write. */
654                 if ( moi->moi_flag & MOI_READER ) {
655                         moi = *moip;
656                         LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
657                 } else {
658                 /* This op is continuing an existing write txn */
659                         *moip = moi;
660                 }
661                 moi->moi_ref++;
662                 if ( !moi->moi_txn ) {
663                         if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) {
664                                 moi->moi_txn = mdb_tool_txn;
665                         } else {
666                                 int flag = 0;
667                                 if ( get_lazyCommit( op ))
668                                         flag |= MDB_NOMETASYNC;
669                                 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, flag, &moi->moi_txn );
670                                 if (rc) {
671                                         Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
672                                                 mdb_strerror(rc), rc, 0 );
673                                 }
674                                 return rc;
675                         }
676                 }
677                 return 0;
678         }
679
680         /* OK, this is a reader */
681         if ( !moi->moi_txn ) {
682                 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) {
683                         moi->moi_txn = mdb_tool_txn;
684                         goto ok;
685                 }
686                 if ( !ctx ) {
687                         /* Shouldn't happen unless we're single-threaded */
688                         rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
689                         if (rc) {
690                                 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
691                                         mdb_strerror(rc), rc, 0 );
692                         }
693                         return rc;
694                 }
695                 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
696                         rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
697                         if (rc) {
698                                 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
699                                         mdb_strerror(rc), rc, 0 );
700                                 return rc;
701                         }
702                         data = moi->moi_txn;
703                         if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
704                                 data, mdb_reader_free, NULL, NULL ) ) ) {
705                                 mdb_txn_abort( moi->moi_txn );
706                                 moi->moi_txn = NULL;
707                                 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
708                                         rc, 0, 0 );
709                                 return rc;
710                         }
711                 } else {
712                         moi->moi_txn = data;
713                         renew = 1;
714                 }
715                 moi->moi_flag |= MOI_READER;
716         }
717 ok:
718         if ( moi->moi_ref < 1 ) {
719                 moi->moi_ref = 0;
720         }
721         if ( renew ) {
722                 rc = mdb_txn_renew( moi->moi_txn );
723                 assert(!rc);
724         }
725         moi->moi_ref++;
726         if ( *moip != moi )
727                 *moip = moi;
728
729         return 0;
730 }
731
732 #ifdef LDAP_X_TXN
733 int mdb_txn( Operation *op, int txnop, OpExtra **ptr )
734 {
735         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
736         mdb_op_info **moip = (mdb_op_info **)ptr, *moi = *moip;
737         int rc;
738
739         switch( txnop ) {
740         case SLAP_TXN_BEGIN:
741                 rc = mdb_opinfo_get( op, mdb, 0, moip );
742                 if ( !rc ) {
743                         moi = *moip;
744                         moi->moi_flag |= MOI_KEEPER;
745                 }
746                 return rc;
747         case SLAP_TXN_COMMIT:
748                 rc = mdb_txn_commit( moi->moi_txn );
749                 if ( rc )
750                         mdb->mi_numads = 0;
751                 op->o_tmpfree( moi, op->o_tmpmemctx );
752                 return rc;
753         case SLAP_TXN_ABORT:
754                 mdb->mi_numads = 0;
755                 mdb_txn_abort( moi->moi_txn );
756                 op->o_tmpfree( moi, op->o_tmpmemctx );
757                 return 0;
758         }
759         return LDAP_OTHER;
760 }
761 #endif
762
763 /* Count up the sizes of the components of an entry */
764 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
765         Ecount *eh)
766 {
767         ber_len_t len, dlen;
768         int i, nat = 0, nval = 0, nnval = 0, doff = 0;
769         Attribute *a;
770
771         eh->multi = NULL;
772         len = 4*sizeof(int);    /* nattrs, nvals, ocflags, offset */
773         dlen = len;
774         for (a=e->e_attrs; a; a=a->a_next) {
775                 /* For AttributeDesc, we only store the attr index */
776                 nat++;
777                 if (a->a_desc->ad_index >= MDB_MAXADS) {
778                         Debug( LDAP_DEBUG_ANY, "mdb_entry_partsize: too many AttributeDescriptions used\n",
779                                 0, 0, 0 );
780                         return LDAP_OTHER;
781                 }
782                 if (!mdb->mi_adxs[a->a_desc->ad_index]) {
783                         int rc = mdb_ad_get(mdb, txn, a->a_desc);
784                         if (rc)
785                                 return rc;
786                 }
787                 len += 2*sizeof(int);   /* AD index, numvals */
788                 dlen += 2*sizeof(int);
789                 nval += a->a_numvals + 1;       /* empty berval at end */
790                 if (a->a_numvals > mdb->mi_multi_hi)
791                         a->a_flags |= SLAP_ATTR_BIG_MULTI;
792                 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
793                         doff += a->a_numvals;
794                 for (i=0; i<a->a_numvals; i++) {
795                         int alen = a->a_vals[i].bv_len + 1 + sizeof(int);       /* len */
796                         len += alen;
797                         if (a->a_flags & SLAP_ATTR_BIG_MULTI) {
798                                 if (!eh->multi)
799                                         eh->multi = a;
800                         } else {
801                                 dlen += alen;
802                         }
803                 }
804                 if (a->a_nvals != a->a_vals) {
805                         nval += a->a_numvals + 1;
806                         nnval++;
807                         if (a->a_flags & SLAP_ATTR_BIG_MULTI)
808                                 doff += a->a_numvals;
809                         for (i=0; i<a->a_numvals; i++) {
810                                 int alen = a->a_nvals[i].bv_len + 1 + sizeof(int);
811                                 len += alen;
812                                 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI))
813                                         dlen += alen;
814                         }
815                 }
816         }
817         /* padding */
818         dlen = (dlen + sizeof(ID)-1) & ~(sizeof(ID)-1);
819         eh->len = len;
820         eh->dlen = dlen;
821         eh->nattrs = nat;
822         eh->nvals = nval;
823         eh->offset = nat + nval - nnval - doff;
824         return 0;
825 }
826
827 /* Flag bits for an encoded attribute */
828 #define MDB_AT_SORTED   (1<<(sizeof(unsigned int)*CHAR_BIT-1))
829         /* the values are in sorted order */
830 #define MDB_AT_MULTI    (1<<(sizeof(unsigned int)*CHAR_BIT-2))
831         /* the values of this multi-valued attr are stored separately */
832
833 #define MDB_AT_NVALS    (1<<(sizeof(unsigned int)*CHAR_BIT-1))
834         /* this attribute has normalized values */
835
836 /* Flatten an Entry into a buffer. The buffer starts with the count of the
837  * number of attributes in the entry, the total number of values in the
838  * entry, and the e_ocflags. It then contains a list of integers for each
839  * attribute. For each attribute the first integer gives the index of the
840  * matching AttributeDescription, followed by the number of values in the
841  * attribute. If the MDB_AT_SORTED bit of the attr index is set, the
842  * attribute's values are already sorted. If the MDB_AT_MULTI bit of the
843  * attr index is set, the values are stored separately.
844  *
845  * Unfortunately, MDB_AT_MULTI and MDB_AT_SORTED are mutually exclusive;
846  * the DB stores big multi-valued attrs in sorted order but the sorting
847  * is according to the DB order which is not guaranteed to match the
848  * attribute's matching rule ordering. So, drop the sorted flag on big
849  * multi-val attributes, the values will need to be resorted when the
850  * entry is read again.
851  *
852  * If the MDB_AT_NVALS bit of numvals is set, the attribute also has
853  * normalized values present. (Note - a_numvals is an unsigned int, so this
854  * means it's possible to receive an attribute that we can't encode due
855  * to size overflow. In practice, this should not be an issue.)
856  *
857  * Then the length of each value is listed. If there are normalized values,
858  * their lengths come next. This continues for each attribute. After all
859  * of the lengths for the last attribute, the actual values are copied,
860  * with a NUL terminator after each value.
861  * The buffer is padded to the sizeof(ID). The entire buffer size is
862  * precomputed so that a single malloc can be performed.
863  */
864 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh)
865 {
866         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
867         ber_len_t len, i;
868         int rc;
869         Attribute *a;
870         unsigned char *ptr;
871         unsigned int *lp, l;
872
873         Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n",
874                 (long) e->e_id, e->e_dn, 0 );
875
876         /* make sure e->e_ocflags is set */
877         if (is_entry_referral(e))
878                 ;       /* empty */
879
880         lp = (unsigned int *)data->mv_data;
881         *lp++ = eh->nattrs;
882         *lp++ = eh->nvals;
883         *lp++ = (unsigned int)e->e_ocflags;
884         *lp++ = eh->offset;
885         ptr = (unsigned char *)(lp + eh->offset);
886
887         for (a=e->e_attrs; a; a=a->a_next) {
888                 if (!a->a_desc->ad_index)
889                         return LDAP_UNDEFINED_TYPE;
890                 l = mdb->mi_adxs[a->a_desc->ad_index];
891                 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
892                         l |= MDB_AT_MULTI;
893                 else if (a->a_flags & SLAP_ATTR_SORTED_VALS)
894                         l |= MDB_AT_SORTED;
895                 *lp++ = l;
896                 l = a->a_numvals;
897                 if (a->a_nvals != a->a_vals)
898                         l |= MDB_AT_NVALS;
899                 *lp++ = l;
900                 if (a->a_flags & SLAP_ATTR_BIG_MULTI) {
901                         continue;
902                 } else {
903                         if (a->a_vals) {
904                                 for (i=0; a->a_vals[i].bv_val; i++);
905                                 assert( i == a->a_numvals );
906                                 for (i=0; i<a->a_numvals; i++) {
907                                         *lp++ = a->a_vals[i].bv_len;
908                                         memcpy(ptr, a->a_vals[i].bv_val,
909                                                 a->a_vals[i].bv_len);
910                                         ptr += a->a_vals[i].bv_len;
911                                         *ptr++ = '\0';
912                                 }
913                                 if (a->a_nvals != a->a_vals) {
914                                         for (i=0; i<a->a_numvals; i++) {
915                                                 *lp++ = a->a_nvals[i].bv_len;
916                                                 memcpy(ptr, a->a_nvals[i].bv_val,
917                                                         a->a_nvals[i].bv_len);
918                                                 ptr += a->a_nvals[i].bv_len;
919                                                 *ptr++ = '\0';
920                                         }
921                                 }
922                         }
923                 }
924         }
925
926         Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n",
927                 (long) e->e_id, e->e_dn, 0 );
928
929         return 0;
930 }
931
932 /* Retrieve an Entry that was stored using entry_encode above.
933  *
934  * Note: everything is stored in a single contiguous block, so
935  * you can not free individual attributes or names from this
936  * structure. Attempting to do so will likely corrupt memory.
937  */
938
939 int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, ID id, Entry **e)
940 {
941         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
942         int i, j, nattrs, nvals;
943         int rc;
944         Attribute *a;
945         Entry *x;
946         const char *text;
947         AttributeDescription *ad;
948         unsigned int *lp = (unsigned int *)data->mv_data;
949         unsigned char *ptr;
950         BerVarray bptr;
951         MDB_cursor *mvc = NULL;
952
953         Debug( LDAP_DEBUG_TRACE,
954                 "=> mdb_entry_decode:\n",
955                 0, 0, 0 );
956
957         nattrs = *lp++;
958         nvals = *lp++;
959         x = mdb_entry_alloc(op, nattrs, nvals);
960         x->e_ocflags = *lp++;
961         if (!nvals) {
962                 goto done;
963         }
964         a = x->e_attrs;
965         bptr = a->a_vals;
966         i = *lp++;
967         ptr = (unsigned char *)(lp + i);
968
969         for (;nattrs>0; nattrs--) {
970                 int have_nval = 0, multi = 0;
971                 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
972                 i = *lp++;
973                 if (i & MDB_AT_SORTED) {
974                         i ^= MDB_AT_SORTED;
975                         a->a_flags |= SLAP_ATTR_SORTED_VALS;
976                 }
977                 if (i & MDB_AT_MULTI) {
978                         i ^= MDB_AT_MULTI;
979                         a->a_flags |= SLAP_ATTR_BIG_MULTI;
980                         multi = 1;
981                 }
982                 if (i > mdb->mi_numads) {
983                         rc = mdb_ad_read(mdb, txn);
984                         if (rc)
985                                 goto leave;
986                         if (i > mdb->mi_numads) {
987                                 Debug( LDAP_DEBUG_ANY,
988                                         "mdb_entry_decode: attribute index %d not recognized\n",
989                                         i, 0, 0 );
990                                 rc = LDAP_OTHER;
991                                 goto leave;
992                         }
993                 }
994                 a->a_desc = mdb->mi_ads[i];
995                 a->a_numvals = *lp++;
996                 if (a->a_numvals & MDB_AT_NVALS) {
997                         a->a_numvals ^= MDB_AT_NVALS;
998                         have_nval = 1;
999                 }
1000                 a->a_vals = bptr;
1001                 if (multi) {
1002                         if (!mvc) {
1003                                 rc = mdb_cursor_open(txn, mdb->mi_dbis[MDB_ID2VAL], &mvc);
1004                                 if (rc)
1005                                         goto leave;
1006                         }
1007                         mdb_mval_get(op, mvc, id, a, have_nval);
1008                         bptr += a->a_numvals + 1;
1009                         if (have_nval)
1010                                 bptr += a->a_numvals + 1;
1011                 } else {
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
1022                         if (have_nval) {
1023                                 a->a_nvals = bptr;
1024                                 for (i=0; i<a->a_numvals; i++) {
1025                                         bptr->bv_len = *lp++;
1026                                         bptr->bv_val = (char *)ptr;
1027                                         ptr += bptr->bv_len+1;
1028                                         bptr++;
1029                                 }
1030                                 bptr->bv_val = NULL;
1031                                 bptr->bv_len = 0;
1032                                 bptr++;
1033                         } else {
1034                                 a->a_nvals = a->a_vals;
1035                         }
1036                 }
1037
1038                 /* FIXME: This is redundant once a sorted entry is saved into the DB */
1039                 if (( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
1040                         && !(a->a_flags & SLAP_ATTR_SORTED_VALS)) {
1041                         rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
1042                         if ( rc == LDAP_SUCCESS ) {
1043                                 a->a_flags |= SLAP_ATTR_SORTED_VALS;
1044                         } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
1045                                 /* should never happen */
1046                                 Debug( LDAP_DEBUG_ANY,
1047                                         "mdb_entry_decode: attributeType %s value #%d provided more than once\n",
1048                                         a->a_desc->ad_cname.bv_val, j, 0 );
1049                                 goto leave;
1050                         }
1051                 }
1052                 a->a_next = a+1;
1053                 a = a->a_next;
1054         }
1055         a[-1].a_next = NULL;
1056 done:
1057         Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n",
1058                 0, 0, 0 );
1059         *e = x;
1060         rc = 0;
1061
1062 leave:
1063         if (mvc)
1064                 mdb_cursor_close(mvc);
1065         return rc;
1066 }