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