]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/index.c
Hallvard B. Furuseth's patch for cache lock and mutex
[openldap] / servers / slapd / back-bdb / index.c
1 /* index.c - routines for dealing with attribute indexes */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/string.h>
13 #include <ac/socket.h>
14
15 #include "slap.h"
16 #include "back-bdb.h"
17 #include "lutil_hash.h"
18
19 static char presence_keyval[LUTIL_HASH_BYTES] = {0,0,0,1};
20 static struct berval presence_key = {LUTIL_HASH_BYTES, presence_keyval};
21
22 static slap_mask_t index_mask(
23         Backend *be,
24         AttributeDescription *desc,
25         char **dbname,
26         struct berval *atname )
27 {
28         AttributeType *at;
29         slap_mask_t mask = 0;
30
31         bdb_attr_mask( be->be_private, desc, &mask );
32
33         if( mask ) {
34                 *atname = desc->ad_cname;
35                 *dbname = desc->ad_cname.bv_val;
36                 return mask;
37         }
38
39         /* If there is a language tag, did we ever index the base
40          * type? If so, check for mask, otherwise it's not there.
41          */
42         if( slap_ad_is_lang( desc ) && desc != desc->ad_type->sat_ad ) {
43                 /* has language tag */
44                 bdb_attr_mask( be->be_private, desc->ad_type->sat_ad, &mask );
45
46                 if ( mask && ( mask ^ SLAP_INDEX_NOLANG ) ) {
47                         *atname = desc->ad_type->sat_cname;
48                         *dbname = desc->ad_type->sat_cname.bv_val;
49                         return mask;
50                 }
51         }
52
53         /* see if supertype defined mask for its subtypes */
54         for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
55                 /* If no AD, we've never indexed this type */
56                 if ( !at->sat_ad ) continue;
57
58                 bdb_attr_mask( be->be_private, at->sat_ad, &mask );
59
60                 if ( mask && ( mask ^ SLAP_INDEX_NOSUBTYPES ) ) {
61                         *atname = at->sat_cname;
62                         *dbname = at->sat_cname.bv_val;
63                         return mask;
64                 }
65         }
66
67         return 0;
68 }
69
70 int bdb_index_is_indexed(
71         Backend *be,
72         AttributeDescription *desc )
73 {
74         slap_mask_t mask;
75         char *dbname;
76         struct berval prefix;
77
78         mask = index_mask( be, desc, &dbname, &prefix );
79
80         if( mask == 0 ) {
81                 return LDAP_INAPPROPRIATE_MATCHING;
82         }
83
84         return LDAP_SUCCESS;
85 }
86
87 int bdb_index_param(
88         Backend *be,
89         AttributeDescription *desc,
90         int ftype,
91         DB **dbp,
92         slap_mask_t *maskp,
93         struct berval *prefixp )
94 {
95         int rc;
96         slap_mask_t mask;
97         DB *db;
98         char *dbname;
99
100         mask = index_mask( be, desc, &dbname, prefixp );
101
102         if( mask == 0 ) {
103                 return LDAP_INAPPROPRIATE_MATCHING;
104         }
105
106         rc = bdb_db_cache( be, dbname, &db );
107
108         if( rc != LDAP_SUCCESS ) {
109                 return rc;
110         }
111
112         switch( ftype ) {
113         case LDAP_FILTER_PRESENT:
114                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
115                         goto done;
116                 }
117                 break;
118
119         case LDAP_FILTER_APPROX:
120                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
121                         goto done;
122                 }
123                 /* fall thru */
124
125         case LDAP_FILTER_EQUALITY:
126                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
127                         goto done;
128                 }
129                 break;
130
131         case LDAP_FILTER_SUBSTRINGS:
132                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
133                         goto done;
134                 }
135                 break;
136
137         default:
138                 return LDAP_OTHER;
139         }
140
141         return LDAP_INAPPROPRIATE_MATCHING;
142
143 done:
144         *dbp = db;
145         *maskp = mask;
146         return LDAP_SUCCESS;
147 }
148
149 static int indexer(
150         Backend *be,
151         DB_TXN *txn,
152         char *dbname,
153         struct berval *atname,
154         BerVarray vals,
155         ID id,
156         int op,
157         slap_mask_t mask )
158 {
159         int rc, i;
160         const char *text;
161         DB *db;
162         AttributeDescription *ad = NULL;
163         struct berval *keys;
164
165         assert( mask );
166
167         rc = bdb_db_cache( be, dbname, &db );
168         
169         if ( rc != LDAP_SUCCESS ) {
170 #ifdef NEW_LOGGING
171                 LDAP_LOG(( "index", LDAP_LEVEL_ERR,
172                         "bdb_index_read: Could not open DB %s\n", dbname));
173 #else
174                 Debug( LDAP_DEBUG_ANY,
175                         "<= bdb_index_read NULL (could not open %s)\n",
176                         dbname, 0, 0 );
177 #endif
178                 return LDAP_OTHER;
179         }
180
181         rc = slap_bv2ad( atname, &ad, &text );
182         if( rc != LDAP_SUCCESS ) return rc;
183
184         if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
185                 rc = bdb_key_change( be, db, txn, &presence_key, id, op );
186                 if( rc ) {
187                         goto done;
188                 }
189         }
190
191         if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
192                 rc = ad->ad_type->sat_equality->smr_indexer(
193                         LDAP_FILTER_EQUALITY,
194                         mask,
195                         ad->ad_type->sat_syntax,
196                         ad->ad_type->sat_equality,
197                         atname, vals, &keys );
198
199                 if( rc == LDAP_SUCCESS && keys != NULL ) {
200                         for( i=0; keys[i].bv_val != NULL; i++ ) {
201                                 rc = bdb_key_change( be, db, txn, &keys[i], id, op );
202                                 if( rc ) {
203                                         ber_bvarray_free( keys );
204                                         goto done;
205                                 }
206                         }
207                         ber_bvarray_free( keys );
208                 }
209                 rc = LDAP_SUCCESS;
210         }
211
212         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
213                 rc = ad->ad_type->sat_approx->smr_indexer(
214                         LDAP_FILTER_APPROX,
215                         mask,
216                         ad->ad_type->sat_syntax,
217                         ad->ad_type->sat_approx,
218                         atname, vals, &keys );
219
220                 if( rc == LDAP_SUCCESS && keys != NULL ) {
221                         for( i=0; keys[i].bv_val != NULL; i++ ) {
222                                 rc = bdb_key_change( be, db, txn, &keys[i], id, op );
223                                 if( rc ) {
224                                         ber_bvarray_free( keys );
225                                         goto done;
226                                 }
227                         }
228                         ber_bvarray_free( keys );
229                 }
230
231                 rc = LDAP_SUCCESS;
232         }
233
234         if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
235                 rc = ad->ad_type->sat_substr->smr_indexer(
236                         LDAP_FILTER_SUBSTRINGS,
237                         mask,
238                         ad->ad_type->sat_syntax,
239                         ad->ad_type->sat_substr,
240                         atname, vals, &keys );
241
242                 if( rc == LDAP_SUCCESS && keys != NULL ) {
243                         for( i=0; keys[i].bv_val != NULL; i++ ) {
244                                 bdb_key_change( be, db, txn, &keys[i], id, op );
245                                 if( rc ) {
246                                         ber_bvarray_free( keys );
247                                         goto done;
248                                 }
249                         }
250                         ber_bvarray_free( keys );
251                 }
252
253                 rc = LDAP_SUCCESS;
254         }
255
256 done:
257         return rc;
258 }
259
260 static int index_at_values(
261         Backend *be,
262         DB_TXN *txn,
263         AttributeType *type,
264         struct berval *lang,
265         BerVarray vals,
266         ID id,
267         int op )
268 {
269         int rc;
270         slap_mask_t mask = 0;
271
272         if( type->sat_sup ) {
273                 /* recurse */
274                 rc = index_at_values( be, txn,
275                         type->sat_sup, lang,
276                         vals, id, op );
277
278                 if( rc ) return rc;
279         }
280
281         /* If this type has no AD, we've never used it before */
282         if( type->sat_ad ) {
283                 bdb_attr_mask( be->be_private, type->sat_ad, &mask );
284         }
285
286         if( mask ) {
287                 rc = indexer( be, txn, type->sat_cname.bv_val,
288                         &type->sat_cname,
289                         vals, id, op,
290                         mask );
291
292                 if( rc ) return rc;
293         }
294
295         if( lang->bv_len ) {
296                 AttributeDescription *desc;
297
298                 mask = 0;
299
300                 desc = ad_find_lang( type, lang );
301                 if( desc ) {
302                         bdb_attr_mask( be->be_private, desc, &mask );
303                 }
304
305                 if( mask ) {
306                         rc = indexer( be, txn, desc->ad_cname.bv_val,
307                                 &desc->ad_cname,
308                                 vals, id, op,
309                                 mask );
310
311                         if( rc ) {
312                                 return rc;
313                         }
314                 }
315         }
316
317         return LDAP_SUCCESS;
318 }
319
320 int bdb_index_values(
321         Backend *be,
322         DB_TXN *txn,
323         AttributeDescription *desc,
324         BerVarray vals,
325         ID id,
326         int op )
327 {
328         int rc;
329
330         rc = index_at_values( be, txn,
331                 desc->ad_type, &desc->ad_lang,
332                 vals, id, op );
333
334         return rc;
335 }
336
337 int
338 bdb_index_entry(
339         Backend *be,
340         DB_TXN *txn,
341         int op,
342         Entry   *e,
343         Attribute *ap )
344 {
345         int rc;
346
347 #ifdef NEW_LOGGING
348         LDAP_LOG(( "index", LDAP_LEVEL_ENTRY,
349                 "index_entry: %s (%s) %ld\n",
350                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
351                 e->e_dn, (long) e->e_id ));
352 #else
353         Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
354                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
355                 (long) e->e_id, e->e_dn );
356 #endif
357
358         /* add each attribute to the indexes */
359         for ( ; ap != NULL; ap = ap->a_next ) {
360                 rc = bdb_index_values( be, txn,
361                         ap->a_desc, ap->a_vals, e->e_id, op );
362
363                 if( rc != LDAP_SUCCESS ) {
364 #ifdef NEW_LOGGING
365                         LDAP_LOG(( "index", LDAP_LEVEL_ENTRY,
366                                 "index_entry: failure (%d)\n", rc ));
367 #else
368                         Debug( LDAP_DEBUG_TRACE,
369                                 "<= index_entry_%s( %ld, \"%s\" ) failure\n",
370                                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
371                                 (long) e->e_id, e->e_dn );
372 #endif
373                         return rc;
374                 }
375         }
376
377 #ifdef NEW_LOGGING
378         LDAP_LOG(( "index", LDAP_LEVEL_ENTRY,
379                 "index_entry: success\n" ));
380 #else
381         Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
382                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
383                 (long) e->e_id, e->e_dn );
384 #endif
385
386         return LDAP_SUCCESS;
387 }