]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/attr.c
Use sorted array for indexed attrs instead of AVL tree
[openldap] / servers / slapd / back-bdb / attr.c
1 /* attr.c - backend routines for dealing with attributes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2005 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/socket.h>
22 #include <ac/string.h>
23
24 #include "slap.h"
25 #include "back-bdb.h"
26 #include "lutil.h"
27
28 unsigned
29 bdb_attr_slot( struct bdb_info *bdb, AttributeDescription *ad )
30 {
31         unsigned base = 0, cursor = 0;
32         unsigned n = bdb->bi_nattrs;
33         int val;
34         
35         while ( 0 < n ) {
36                 int pivot = n >> 1;
37                 cursor = base + pivot;
38
39                 val = SLAP_PTRCMP( ad, bdb->bi_attrs[cursor]->ai_desc );
40                 if ( val < 0 ) {
41                         n = pivot;
42                 } else if ( val > 0 ) {
43                         base = cursor + 1;
44                         n -= pivot + 1;
45                 } else {
46                         return cursor;
47                 }
48         }
49         if ( val > 0 )
50                 ++cursor;
51         return cursor;
52 }
53
54 static int
55 ainfo_insert( struct bdb_info *bdb, AttrInfo *a )
56 {
57         unsigned x = bdb_attr_slot( bdb, a->ai_desc );
58
59         /* Is it a dup? */
60         if ( x < bdb->bi_nattrs && bdb->bi_attrs[x]->ai_desc == a->ai_desc )
61                 return -1;
62
63         bdb->bi_attrs = ch_realloc( bdb->bi_attrs, ( bdb->bi_nattrs+1 ) * 
64                 sizeof( AttrInfo * ));
65         if ( x < bdb->bi_nattrs )
66                 AC_MEMCPY( &bdb->bi_attrs[x+1], &bdb->bi_attrs[x],
67                         ( bdb->bi_nattrs - x ) * sizeof( AttrInfo *));
68         bdb->bi_attrs[x] = a;
69         bdb->bi_nattrs++;
70         return 0;
71 }
72
73 AttrInfo *
74 bdb_attr_mask(
75         struct bdb_info *bdb,
76         AttributeDescription *desc )
77 {
78         unsigned i = bdb_attr_slot( bdb, desc );
79         return ( i < bdb->bi_nattrs && bdb->bi_attrs[i]->ai_desc == desc ) ?
80                 bdb->bi_attrs[i] : NULL;
81 }
82
83 int
84 bdb_attr_index_config(
85         struct bdb_info *bdb,
86         const char              *fname,
87         int                     lineno,
88         int                     argc,
89         char            **argv )
90 {
91         int rc;
92         int     i;
93         slap_mask_t mask;
94         char **attrs;
95         char **indexes = NULL;
96
97         attrs = ldap_str2charray( argv[0], "," );
98
99         if( attrs == NULL ) {
100                 fprintf( stderr, "%s: line %d: "
101                         "no attributes specified: %s\n",
102                         fname, lineno, argv[0] );
103                 return LDAP_PARAM_ERROR;
104         }
105
106         if ( argc > 1 ) {
107                 indexes = ldap_str2charray( argv[1], "," );
108
109                 if( indexes == NULL ) {
110                         fprintf( stderr, "%s: line %d: "
111                                 "no indexes specified: %s\n",
112                                 fname, lineno, argv[1] );
113                         return LDAP_PARAM_ERROR;
114                 }
115         }
116
117         if( indexes == NULL ) {
118                 mask = bdb->bi_defaultmask;
119
120         } else {
121                 mask = 0;
122
123                 for ( i = 0; indexes[i] != NULL; i++ ) {
124                         slap_mask_t index;
125                         rc = slap_str2index( indexes[i], &index );
126
127                         if( rc != LDAP_SUCCESS ) {
128                                 fprintf( stderr, "%s: line %d: "
129                                         "index type \"%s\" undefined\n",
130                                         fname, lineno, indexes[i] );
131                                 return LDAP_PARAM_ERROR;
132                         }
133
134                         mask |= index;
135                 }
136         }
137
138         if( !mask ) {
139                 fprintf( stderr, "%s: line %d: "
140                         "no indexes selected\n",
141                         fname, lineno );
142                 return LDAP_PARAM_ERROR;
143         }
144
145         for ( i = 0; attrs[i] != NULL; i++ ) {
146                 AttrInfo        *a;
147                 AttributeDescription *ad;
148                 const char *text;
149 #ifdef LDAP_COMP_MATCH
150                 ComponentReference* cr = NULL;
151                 AttrInfo *a_cr = NULL;
152 #endif
153
154                 if( strcasecmp( attrs[i], "default" ) == 0 ) {
155                         bdb->bi_defaultmask |= mask;
156                         continue;
157                 }
158
159 #ifdef LDAP_COMP_MATCH
160                 if ( is_component_reference( attrs[i] ) ) {
161                         rc = extract_component_reference( attrs[i], &cr );
162                         if ( rc != LDAP_SUCCESS ) {
163                                 fprintf( stderr, "%s: line %d: "
164                                         "index component reference\"%s\" undefined\n",
165                                         fname, lineno, attrs[i] );
166                                 return rc;
167                         }
168                         cr->cr_indexmask = mask;
169                         /*
170                          * After extracting a component reference
171                          * only the name of a attribute will be remaining
172                          */
173                 } else {
174                         cr = NULL;
175                 }
176 #endif
177                 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
178
179 #ifdef LDAP_COMP_MATCH
180                 a->ai_cr = NULL;
181 #endif
182                 ad = NULL;
183                 rc = slap_str2ad( attrs[i], &ad, &text );
184
185                 if( rc != LDAP_SUCCESS ) {
186                         fprintf( stderr, "%s: line %d: "
187                                 "index attribute \"%s\" undefined\n",
188                                 fname, lineno, attrs[i] );
189                         return rc;
190                 }
191
192                 if( slap_ad_is_binary( ad ) ) {
193                         fprintf( stderr, "%s: line %d: "
194                                 "index of attribute \"%s\" disallowed\n",
195                                 fname, lineno, attrs[i] );
196                         return LDAP_UNWILLING_TO_PERFORM;
197                 }
198
199                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
200                         ad->ad_type->sat_approx
201                                 && ad->ad_type->sat_approx->smr_indexer
202                                 && ad->ad_type->sat_approx->smr_filter ) )
203                 {
204                         fprintf( stderr, "%s: line %d: "
205                                 "approx index of attribute \"%s\" disallowed\n",
206                                 fname, lineno, attrs[i] );
207                         return LDAP_INAPPROPRIATE_MATCHING;
208                 }
209
210                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
211                         ad->ad_type->sat_equality
212                                 && ad->ad_type->sat_equality->smr_indexer
213                                 && ad->ad_type->sat_equality->smr_filter ) )
214                 {
215                         fprintf( stderr, "%s: line %d: "
216                                 "equality index of attribute \"%s\" disallowed\n",
217                                 fname, lineno, attrs[i] );
218                         return LDAP_INAPPROPRIATE_MATCHING;
219                 }
220
221                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
222                         ad->ad_type->sat_substr
223                                 && ad->ad_type->sat_substr->smr_indexer
224                                 && ad->ad_type->sat_substr->smr_filter ) )
225                 {
226                         fprintf( stderr, "%s: line %d: "
227                                 "substr index of attribute \"%s\" disallowed\n",
228                                 fname, lineno, attrs[i] );
229                         return LDAP_INAPPROPRIATE_MATCHING;
230                 }
231
232                 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
233                         ad->ad_cname.bv_val, mask, 0 ); 
234
235                 a->ai_desc = ad;
236
237                 if ( bdb->bi_flags & BDB_IS_OPEN ) {
238                         a->ai_indexmask = 0;
239                         a->ai_newmask = mask;
240                 } else {
241                         a->ai_indexmask = mask;
242                         a->ai_newmask = 0;
243                 }
244
245 #ifdef LDAP_COMP_MATCH
246                 if ( cr ) {
247                         a_cr = bdb_attr_mask( bdb, ad );
248                         if ( a_cr ) {
249                                 /*
250                                  * AttrInfo is already in AVL
251                                  * just add the extracted component reference
252                                  * in the AttrInfo
253                                  */
254                                 rc = insert_component_reference( cr, &a_cr->ai_cr );
255                                 if ( rc != LDAP_SUCCESS) {
256                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
257                                         return LDAP_PARAM_ERROR;
258                                 }
259                                 continue;
260                         } else {
261                                 rc = insert_component_reference( cr, &a->ai_cr );
262                                 if ( rc != LDAP_SUCCESS) {
263                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
264                                         return LDAP_PARAM_ERROR;
265                                 }
266                         }
267                 }
268 #endif
269                 rc = ainfo_insert( bdb, a );
270                 if( rc ) {
271                         if ( bdb->bi_flags & BDB_IS_OPEN ) {
272                                 AttrInfo *b = bdb_attr_mask( bdb, ad );
273                                 /* If we were editing this attr, reset it */
274                                 b->ai_indexmask &= ~BDB_INDEX_DELETING;
275                                 /* If this is leftover from a previous add, commit it */
276                                 if ( b->ai_newmask )
277                                         b->ai_indexmask = b->ai_newmask;
278                                 b->ai_newmask = a->ai_newmask;
279                                 ch_free( a );
280                                 continue;
281                         }
282                         fprintf( stderr, "%s: line %d: duplicate index definition "
283                                 "for attr \"%s\"" SLAPD_CONF_UNKNOWN_IGNORED ".\n",
284                                 fname, lineno, attrs[i] );
285
286                         return LDAP_PARAM_ERROR;
287                 }
288         }
289
290         ldap_charray_free( attrs );
291         if ( indexes != NULL ) ldap_charray_free( indexes );
292
293         return LDAP_SUCCESS;
294 }
295
296 static int
297 bdb_attr_index_unparser( void *v1, void *v2 )
298 {
299         AttrInfo *ai = v1;
300         BerVarray *bva = v2;
301         struct berval bv;
302         char *ptr;
303
304         slap_index2bvlen( ai->ai_indexmask, &bv );
305         if ( bv.bv_len ) {
306                 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
307                 ptr = ch_malloc( bv.bv_len+1 );
308                 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
309                 *bv.bv_val++ = ' ';
310                 slap_index2bv( ai->ai_indexmask, &bv );
311                 bv.bv_val = ptr;
312                 ber_bvarray_add( bva, &bv );
313         }
314         return 0;
315 }
316
317 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
318 static AttrInfo aidef = { &addef };
319
320 void
321 bdb_attr_index_unparse( struct bdb_info *bdb, BerVarray *bva )
322 {
323         int i;
324
325         if ( bdb->bi_defaultmask ) {
326                 aidef.ai_indexmask = bdb->bi_defaultmask;
327                 bdb_attr_index_unparser( &aidef, bva );
328         }
329         for ( i=0; i<bdb->bi_nattrs; i++ )
330                 bdb_attr_index_unparser( bdb->bi_attrs[i], bva );
331 }
332
333 void
334 bdb_attr_info_free( AttrInfo *ai )
335 {
336 #ifdef LDAP_COMP_MATCH
337         free( ai->ai_cr );
338 #endif
339         free( ai );
340 }
341
342 void
343 bdb_attr_index_destroy( struct bdb_info *bdb )
344 {
345         int i;
346
347         for ( i=0; i<bdb->bi_nattrs; i++ ) 
348                 bdb_attr_info_free( bdb->bi_attrs[i] );
349
350         free( bdb->bi_attrs );
351 }
352
353 void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad )
354 {
355         unsigned i;
356
357         i = bdb_attr_slot( bdb, ad );
358         if ( i < bdb->bi_nattrs && bdb->bi_attrs[i]->ai_desc == ad ) {
359                 bdb_attr_info_free( bdb->bi_attrs[i] );
360                 bdb->bi_nattrs--;
361                 for (; i<bdb->bi_nattrs; i++)
362                         bdb->bi_attrs[i] = bdb->bi_attrs[i+1];
363         }
364 }
365
366 void bdb_attr_flush( struct bdb_info *bdb )
367 {
368         int i;
369
370         for ( i=0; i<bdb->bi_nattrs; i++ ) {
371                 if ( bdb->bi_attrs[i]->ai_indexmask & BDB_INDEX_DELETING ) {
372                         int j;
373                         bdb_attr_info_free( bdb->bi_attrs[i] );
374                         bdb->bi_nattrs--;
375                         for (j=i; j<bdb->bi_nattrs; j++)
376                                 bdb->bi_attrs[j] = bdb->bi_attrs[j+1];
377                         i--;
378                 }
379         }
380 }