]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/index.c
Import back-mdb
[openldap] / servers / slapd / back-mdb / index.c
1 /* index.c - routines for dealing with attribute indexes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2011 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
21 #include <ac/string.h>
22 #include <ac/socket.h>
23
24 #include "slap.h"
25 #include "back-mdb.h"
26 #include "lutil_hash.h"
27
28 static char presence_keyval[] = {0,0};
29 static struct berval presence_key = BER_BVC(presence_keyval);
30
31 AttrInfo *mdb_index_mask(
32         Backend *be,
33         AttributeDescription *desc,
34         struct berval *atname )
35 {
36         AttributeType *at;
37         AttrInfo *ai = mdb_attr_mask( be->be_private, desc );
38
39         if( ai ) {
40                 *atname = desc->ad_cname;
41                 return ai;
42         }
43
44         /* If there is a tagging option, did we ever index the base
45          * type? If so, check for mask, otherwise it's not there.
46          */
47         if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) {
48                 /* has tagging option */
49                 ai = mdb_attr_mask( be->be_private, desc->ad_type->sat_ad );
50
51                 if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOTAGS ) ) {
52                         *atname = desc->ad_type->sat_cname;
53                         return ai;
54                 }
55         }
56
57         /* see if supertype defined mask for its subtypes */
58         for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
59                 /* If no AD, we've never indexed this type */
60                 if ( !at->sat_ad ) continue;
61
62                 ai = mdb_attr_mask( be->be_private, at->sat_ad );
63
64                 if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOSUBTYPES ) ) {
65                         *atname = at->sat_cname;
66                         return ai;
67                 }
68         }
69
70         return 0;
71 }
72
73 /* This function is only called when evaluating search filters.
74  */
75 int mdb_index_param(
76         Backend *be,
77         AttributeDescription *desc,
78         int ftype,
79         MDB_dbi *dbip,
80         slap_mask_t *maskp,
81         struct berval *prefixp )
82 {
83         AttrInfo *ai;
84         slap_mask_t mask, type = 0;
85
86         ai = mdb_index_mask( be, desc, prefixp );
87
88         if ( !ai ) {
89 #ifdef MDB_MONITOR_IDX
90                 switch ( ftype ) {
91                 case LDAP_FILTER_PRESENT:
92                         type = SLAP_INDEX_PRESENT;
93                         break;
94                 case LDAP_FILTER_APPROX:
95                         type = SLAP_INDEX_APPROX;
96                         break;
97                 case LDAP_FILTER_EQUALITY:
98                         type = SLAP_INDEX_EQUALITY;
99                         break;
100                 case LDAP_FILTER_SUBSTRINGS:
101                         type = SLAP_INDEX_SUBSTR;
102                         break;
103                 default:
104                         return LDAP_INAPPROPRIATE_MATCHING;
105                 }
106                 mdb_monitor_idx_add( be->be_private, desc, type );
107 #endif /* MDB_MONITOR_IDX */
108
109                 return LDAP_INAPPROPRIATE_MATCHING;
110         }
111         mask = ai->ai_indexmask;
112
113         switch( ftype ) {
114         case LDAP_FILTER_PRESENT:
115                 type = SLAP_INDEX_PRESENT;
116                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
117                         *prefixp = presence_key;
118                         goto done;
119                 }
120                 break;
121
122         case LDAP_FILTER_APPROX:
123                 type = SLAP_INDEX_APPROX;
124                 if ( desc->ad_type->sat_approx ) {
125                         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
126                                 goto done;
127                         }
128                         break;
129                 }
130
131                 /* Use EQUALITY rule and index for approximate match */
132                 /* fall thru */
133
134         case LDAP_FILTER_EQUALITY:
135                 type = SLAP_INDEX_EQUALITY;
136                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
137                         goto done;
138                 }
139                 break;
140
141         case LDAP_FILTER_SUBSTRINGS:
142                 type = SLAP_INDEX_SUBSTR;
143                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
144                         goto done;
145                 }
146                 break;
147
148         default:
149                 return LDAP_OTHER;
150         }
151
152 #ifdef MDB_MONITOR_IDX
153         mdb_monitor_idx_add( be->be_private, desc, type );
154 #endif /* MDB_MONITOR_IDX */
155
156         return LDAP_INAPPROPRIATE_MATCHING;
157
158 done:
159         *dbip = ai->ai_dbi;
160         *maskp = mask;
161         return LDAP_SUCCESS;
162 }
163
164 static int indexer(
165         Operation *op,
166         MDB_txn *txn,
167         MDB_dbi dbi,
168         AttributeDescription *ad,
169         struct berval *atname,
170         BerVarray vals,
171         ID id,
172         int opid,
173         slap_mask_t mask )
174 {
175         int rc, i;
176         struct berval *keys;
177
178         assert( mask != 0 );
179
180         if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
181                 rc = mdb_key_change( op->o_bd, txn, dbi, &presence_key, id, opid );
182                 if( rc ) {
183                         goto done;
184                 }
185         }
186
187         if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
188                 rc = ad->ad_type->sat_equality->smr_indexer(
189                         LDAP_FILTER_EQUALITY,
190                         mask,
191                         ad->ad_type->sat_syntax,
192                         ad->ad_type->sat_equality,
193                         atname, vals, &keys, op->o_tmpmemctx );
194
195                 if( rc == LDAP_SUCCESS && keys != NULL ) {
196                         for( i=0; keys[i].bv_val != NULL; i++ ) {
197                                 rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
198                                 if( rc ) {
199                                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
200                                         goto done;
201                                 }
202                         }
203                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
204                 }
205                 rc = LDAP_SUCCESS;
206         }
207
208         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
209                 rc = ad->ad_type->sat_approx->smr_indexer(
210                         LDAP_FILTER_APPROX,
211                         mask,
212                         ad->ad_type->sat_syntax,
213                         ad->ad_type->sat_approx,
214                         atname, vals, &keys, op->o_tmpmemctx );
215
216                 if( rc == LDAP_SUCCESS && keys != NULL ) {
217                         for( i=0; keys[i].bv_val != NULL; i++ ) {
218                                 rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
219                                 if( rc ) {
220                                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
221                                         goto done;
222                                 }
223                         }
224                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
225                 }
226
227                 rc = LDAP_SUCCESS;
228         }
229
230         if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
231                 rc = ad->ad_type->sat_substr->smr_indexer(
232                         LDAP_FILTER_SUBSTRINGS,
233                         mask,
234                         ad->ad_type->sat_syntax,
235                         ad->ad_type->sat_substr,
236                         atname, vals, &keys, op->o_tmpmemctx );
237
238                 if( rc == LDAP_SUCCESS && keys != NULL ) {
239                         for( i=0; keys[i].bv_val != NULL; i++ ) {
240                                 rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
241                                 if( rc ) {
242                                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
243                                         goto done;
244                                 }
245                         }
246                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
247                 }
248
249                 rc = LDAP_SUCCESS;
250         }
251
252 done:
253         switch( rc ) {
254         /* The callers all know how to deal with these results */
255         case 0:
256                 break;
257         /* Anything else is bad news */
258         default:
259                 rc = LDAP_OTHER;
260         }
261         return rc;
262 }
263
264 static int index_at_values(
265         Operation *op,
266         MDB_txn *txn,
267         AttributeDescription *ad,
268         AttributeType *type,
269         struct berval *tags,
270         BerVarray vals,
271         ID id,
272         int opid )
273 {
274         int rc;
275         slap_mask_t mask = 0;
276         int ixop = opid;
277         AttrInfo *ai = NULL;
278
279         if ( opid == MDB_INDEX_UPDATE_OP )
280                 ixop = SLAP_INDEX_ADD_OP;
281
282         if( type->sat_sup ) {
283                 /* recurse */
284                 rc = index_at_values( op, txn, NULL,
285                         type->sat_sup, tags,
286                         vals, id, opid );
287
288                 if( rc ) return rc;
289         }
290
291         /* If this type has no AD, we've never used it before */
292         if( type->sat_ad ) {
293                 ai = mdb_attr_mask( op->o_bd->be_private, type->sat_ad );
294                 if ( ai ) {
295 #ifdef LDAP_COMP_MATCH
296                         /* component indexing */
297                         if ( ai->ai_cr ) {
298                                 ComponentReference *cr;
299                                 for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
300                                         rc = indexer( op, txn, ai->ai_dbi, cr->cr_ad, &type->sat_cname,
301                                                 cr->cr_nvals, id, ixop,
302                                                 cr->cr_indexmask );
303                                 }
304                         }
305 #endif
306                         ad = type->sat_ad;
307                         /* If we're updating the index, just set the new bits that aren't
308                          * already in the old mask.
309                          */
310                         if ( opid == MDB_INDEX_UPDATE_OP )
311                                 mask = ai->ai_newmask & ~ai->ai_indexmask;
312                         else
313                         /* For regular updates, if there is a newmask use it. Otherwise
314                          * just use the old mask.
315                          */
316                                 mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
317                         if( mask ) {
318                                 rc = indexer( op, txn, ai->ai_dbi, ad, &type->sat_cname,
319                                         vals, id, ixop, mask );
320
321                                 if( rc ) return rc;
322                         }
323                 }
324         }
325
326         if( tags->bv_len ) {
327                 AttributeDescription *desc;
328
329                 desc = ad_find_tags( type, tags );
330                 if( desc ) {
331                         ai = mdb_attr_mask( op->o_bd->be_private, desc );
332
333                         if( ai ) {
334                                 if ( opid == MDB_INDEX_UPDATE_OP )
335                                         mask = ai->ai_newmask & ~ai->ai_indexmask;
336                                 else
337                                         mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
338                                 if ( mask ) {
339                                         rc = indexer( op, txn, ai->ai_dbi, desc, &desc->ad_cname,
340                                                 vals, id, ixop, mask );
341
342                                         if( rc ) {
343                                                 return rc;
344                                         }
345                                 }
346                         }
347                 }
348         }
349
350         return LDAP_SUCCESS;
351 }
352
353 int mdb_index_values(
354         Operation *op,
355         MDB_txn *txn,
356         AttributeDescription *desc,
357         BerVarray vals,
358         ID id,
359         int opid )
360 {
361         int rc;
362
363         /* Never index ID 0 */
364         if ( id == 0 )
365                 return 0;
366
367         rc = index_at_values( op, txn, desc,
368                 desc->ad_type, &desc->ad_tags,
369                 vals, id, opid );
370
371         return rc;
372 }
373
374 /* Get the list of which indices apply to this attr */
375 int
376 mdb_index_recset(
377         struct mdb_info *mdb,
378         Attribute *a,
379         AttributeType *type,
380         struct berval *tags,
381         IndexRec *ir )
382 {
383         int rc, slot;
384         AttrList *al;
385
386         if( type->sat_sup ) {
387                 /* recurse */
388                 rc = mdb_index_recset( mdb, a, type->sat_sup, tags, ir );
389                 if( rc ) return rc;
390         }
391         /* If this type has no AD, we've never used it before */
392         if( type->sat_ad ) {
393                 slot = mdb_attr_slot( mdb, type->sat_ad, NULL );
394                 if ( slot >= 0 ) {
395                         ir[slot].ai = mdb->mi_attrs[slot];
396                         al = ch_malloc( sizeof( AttrList ));
397                         al->attr = a;
398                         al->next = ir[slot].attrs;
399                         ir[slot].attrs = al;
400                 }
401         }
402         if( tags->bv_len ) {
403                 AttributeDescription *desc;
404
405                 desc = ad_find_tags( type, tags );
406                 if( desc ) {
407                         slot = mdb_attr_slot( mdb, desc, NULL );
408                         if ( slot >= 0 ) {
409                                 ir[slot].ai = mdb->mi_attrs[slot];
410                                 al = ch_malloc( sizeof( AttrList ));
411                                 al->attr = a;
412                                 al->next = ir[slot].attrs;
413                                 ir[slot].attrs = al;
414                         }
415                 }
416         }
417         return LDAP_SUCCESS;
418 }
419
420 /* Apply the indices for the recset */
421 int mdb_index_recrun(
422         Operation *op,
423         struct mdb_info *mdb,
424         IndexRec *ir0,
425         ID id,
426         int base )
427 {
428         IndexRec *ir;
429         AttrList *al;
430         int i, rc = 0;
431
432         /* Never index ID 0 */
433         if ( id == 0 )
434                 return 0;
435
436         for (i=base; i<mdb->mi_nattrs; i+=slap_tool_thread_max) {
437                 ir = ir0 + i;
438                 if ( !ir->ai ) continue;
439                 while (( al = ir->attrs )) {
440                         ir->attrs = al->next;
441                         rc = indexer( op, NULL, ir->ai->ai_dbi, ir->ai->ai_desc,
442                                 &ir->ai->ai_desc->ad_type->sat_cname,
443                                 al->attr->a_nvals, id, SLAP_INDEX_ADD_OP,
444                                 ir->ai->ai_indexmask );
445                         free( al );
446                         if ( rc ) break;
447                 }
448         }
449         return rc;
450 }
451
452 int
453 mdb_index_entry(
454         Operation *op,
455         MDB_txn *txn,
456         int opid,
457         Entry   *e )
458 {
459         int rc;
460         Attribute *ap = e->e_attrs;
461 #if 0 /* ifdef LDAP_COMP_MATCH */
462         ComponentReference *cr_list = NULL;
463         ComponentReference *cr = NULL, *dupped_cr = NULL;
464         void* decoded_comp;
465         ComponentSyntaxInfo* csi_attr;
466         Syntax* syn;
467         AttributeType* at;
468         int i, num_attr;
469         void* mem_op;
470         struct berval value = {0};
471 #endif
472
473         /* Never index ID 0 */
474         if ( e->e_id == 0 )
475                 return 0;
476
477         Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
478                 opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
479                 (long) e->e_id, e->e_dn );
480
481         /* add each attribute to the indexes */
482         for ( ; ap != NULL; ap = ap->a_next ) {
483 #if 0 /* ifdef LDAP_COMP_MATCH */
484                 AttrInfo *ai;
485                 /* see if attribute has components to be indexed */
486                 ai = mdb_attr_mask( op->o_bd->be_private, ap->a_desc->ad_type->sat_ad );
487                 if ( !ai ) continue;
488                 cr_list = ai->ai_cr;
489                 if ( attr_converter && cr_list ) {
490                         syn = ap->a_desc->ad_type->sat_syntax;
491                         ap->a_comp_data = op->o_tmpalloc( sizeof( ComponentData ), op->o_tmpmemctx );
492                         /* Memory chunk(nibble) pre-allocation for decoders */
493                         mem_op = nibble_mem_allocator ( 1024*16, 1024*4 );
494                         ap->a_comp_data->cd_mem_op = mem_op;
495                         for( cr = cr_list ; cr ; cr = cr->cr_next ) {
496                                 /* count how many values in an attribute */
497                                 for( num_attr=0; ap->a_vals[num_attr].bv_val != NULL; num_attr++ );
498                                 num_attr++;
499                                 cr->cr_nvals = (BerVarray)op->o_tmpalloc( sizeof( struct berval )*num_attr, op->o_tmpmemctx );
500                                 for( i=0; ap->a_vals[i].bv_val != NULL; i++ ) {
501                                         /* decoding attribute value */
502                                         decoded_comp = attr_converter ( ap, syn, &ap->a_vals[i] );
503                                         if ( !decoded_comp )
504                                                 return LDAP_DECODING_ERROR;
505                                         /* extracting the referenced component */
506                                         dupped_cr = dup_comp_ref( op, cr );
507                                         csi_attr = ((ComponentSyntaxInfo*)decoded_comp)->csi_comp_desc->cd_extract_i( mem_op, dupped_cr, decoded_comp );
508                                         if ( !csi_attr )
509                                                 return LDAP_DECODING_ERROR;
510                                         cr->cr_asn_type_id = csi_attr->csi_comp_desc->cd_type_id;
511                                         cr->cr_ad = (AttributeDescription*)get_component_description ( cr->cr_asn_type_id );
512                                         if ( !cr->cr_ad )
513                                                 return LDAP_INVALID_SYNTAX;
514                                         at = cr->cr_ad->ad_type;
515                                         /* encoding the value of component in GSER */
516                                         rc = component_encoder( mem_op, csi_attr, &value );
517                                         if ( rc != LDAP_SUCCESS )
518                                                 return LDAP_ENCODING_ERROR;
519                                         /* Normalize the encoded component values */
520                                         if ( at->sat_equality && at->sat_equality->smr_normalize ) {
521                                                 rc = at->sat_equality->smr_normalize (
522                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
523                                                         at->sat_syntax, at->sat_equality,
524                                                         &value, &cr->cr_nvals[i], op->o_tmpmemctx );
525                                         } else {
526                                                 cr->cr_nvals[i] = value;
527                                         }
528                                 }
529                                 /* The end of BerVarray */
530                                 cr->cr_nvals[num_attr-1].bv_val = NULL;
531                                 cr->cr_nvals[num_attr-1].bv_len = 0;
532                         }
533                         op->o_tmpfree( ap->a_comp_data, op->o_tmpmemctx );
534                         nibble_mem_free ( mem_op );
535                         ap->a_comp_data = NULL;
536                 }
537 #endif
538                 rc = mdb_index_values( op, txn, ap->a_desc,
539                         ap->a_nvals, e->e_id, opid );
540
541                 if( rc != LDAP_SUCCESS ) {
542                         Debug( LDAP_DEBUG_TRACE,
543                                 "<= index_entry_%s( %ld, \"%s\" ) failure\n",
544                                 opid == SLAP_INDEX_ADD_OP ? "add" : "del",
545                                 (long) e->e_id, e->e_dn );
546                         return rc;
547                 }
548         }
549
550         Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
551                 opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
552                 (long) e->e_id, e->e_dn );
553
554         return LDAP_SUCCESS;
555 }