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