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