]> git.sur5r.net Git - openldap/blob - servers/slapd/back-wt/index.c
20af5e6f675c5016cbe510cbdf89ddd125328125
[openldap] / servers / slapd / back-wt / index.c
1 /* OpenLDAP WiredTiger backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2002-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 /* ACKNOWLEDGEMENTS:
17  * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
18  * based on back-bdb for inclusion in OpenLDAP Software.
19  * WiredTiger is a product of MongoDB Inc.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include "back-wt.h"
26 #include "config.h"
27
28 static char presence_keyval[] = {0,0};
29 static struct berval presence_key = BER_BVC(presence_keyval);
30
31 AttrInfo *wt_index_mask(
32         Backend *be,
33         AttributeDescription *desc,
34         struct berval *atname )
35 {
36         AttributeType *at;
37         AttrInfo *ai = wt_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 = wt_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 = wt_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 wt_index_param(
76         Backend *be,
77         AttributeDescription *desc,
78         int ftype,
79         slap_mask_t *maskp,
80         struct berval *prefixp )
81 {
82         AttrInfo *ai;
83         int rc;
84         slap_mask_t mask, type = 0;
85
86         ai = wt_index_mask( be, desc, prefixp );
87
88         if ( !ai ) {
89                 /* TODO: add monitor */
90                 return LDAP_INAPPROPRIATE_MATCHING;
91         }
92         mask = ai->ai_indexmask;
93
94         switch( ftype ) {
95         case LDAP_FILTER_PRESENT:
96                 type = SLAP_INDEX_PRESENT;
97                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
98                         *prefixp = presence_key;
99                         *maskp = mask;
100                         return LDAP_SUCCESS;
101                 }
102                 break;
103
104         case LDAP_FILTER_APPROX:
105                 type = SLAP_INDEX_APPROX;
106                 if ( desc->ad_type->sat_approx ) {
107                         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
108                                 *maskp = mask;
109                                 return LDAP_SUCCESS;
110                         }
111                         break;
112                 }
113
114                 /* Use EQUALITY rule and index for approximate match */
115                 /* fall thru */
116
117         case LDAP_FILTER_EQUALITY:
118                 type = SLAP_INDEX_EQUALITY;
119                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
120                         *maskp = mask;
121                         return LDAP_SUCCESS;
122                 }
123                 break;
124
125         case LDAP_FILTER_SUBSTRINGS:
126                 type = SLAP_INDEX_SUBSTR;
127                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
128                         *maskp = mask;
129                         return LDAP_SUCCESS;
130                 }
131                 break;
132
133         default:
134                 return LDAP_OTHER;
135         }
136
137         /* TODO: add monitor index */
138         return LDAP_INAPPROPRIATE_MATCHING;
139 }
140
141 static int indexer(
142         Operation *op,
143         wt_ctx *wc,
144         AttributeDescription *ad,
145         struct berval *atname,
146         BerVarray vals,
147         ID id,
148         int opid,
149         slap_mask_t mask )
150 {
151         int rc, i;
152         struct berval *keys;
153         WT_CURSOR *cursor = NULL;
154         WT_SESSION *session = wc->session;
155         assert( mask != 0 );
156
157         cursor = wt_ctx_index_cursor(wc, atname, 1);
158         if( !cursor ) {
159                 Debug( LDAP_DEBUG_ANY,
160                            LDAP_XSTRING(indexer)
161                            ": open index cursor failed: %s\n",
162                            atname->bv_val, 0, 0 );
163                 goto done;
164         }
165
166         if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
167                 rc = wt_key_change( op->o_bd, cursor, &presence_key, id, opid );
168                 if( rc ) {
169                         goto done;
170                 }
171         }
172
173         if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
174                 rc = ad->ad_type->sat_equality->smr_indexer(
175                         LDAP_FILTER_EQUALITY,
176                         mask,
177                         ad->ad_type->sat_syntax,
178                         ad->ad_type->sat_equality,
179                         atname, vals, &keys, op->o_tmpmemctx );
180
181                 if( rc == LDAP_SUCCESS && keys != NULL ) {
182                         for( i=0; keys[i].bv_val != NULL; i++ ) {
183                                 rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
184                                 if( rc ) {
185                                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
186                                         goto done;
187                                 }
188                         }
189                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
190                 }
191                 rc = LDAP_SUCCESS;
192         }
193
194         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
195                 rc = ad->ad_type->sat_approx->smr_indexer(
196                         LDAP_FILTER_APPROX,
197                         mask,
198                         ad->ad_type->sat_syntax,
199                         ad->ad_type->sat_approx,
200                         atname, vals, &keys, op->o_tmpmemctx );
201
202                 if( rc == LDAP_SUCCESS && keys != NULL ) {
203                         for( i=0; keys[i].bv_val != NULL; i++ ) {
204                                 rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
205                                 if( rc ) {
206                                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
207                                         goto done;
208                                 }
209                         }
210                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
211                 }
212
213                 rc = LDAP_SUCCESS;
214         }
215
216         if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
217                 rc = ad->ad_type->sat_substr->smr_indexer(
218                         LDAP_FILTER_SUBSTRINGS,
219                         mask,
220                         ad->ad_type->sat_syntax,
221                         ad->ad_type->sat_substr,
222                         atname, vals, &keys, op->o_tmpmemctx );
223
224                 if( rc == LDAP_SUCCESS && keys != NULL ) {
225                         for( i=0; keys[i].bv_val != NULL; i++ ) {
226                                 rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
227                                 if( rc ) {
228                                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
229                                         goto done;
230                                 }
231                         }
232                         ber_bvarray_free_x( keys, op->o_tmpmemctx );
233                 }
234
235                 rc = LDAP_SUCCESS;
236         }
237
238 done:
239         if(cursor){
240                 cursor->close(cursor);
241         }
242         return rc;
243 }
244
245 static int index_at_values(
246         Operation *op,
247         wt_ctx *wc,
248         AttributeDescription *ad,
249         AttributeType *type,
250         struct berval *tags,
251         BerVarray vals,
252         ID id,
253         int opid )
254 {
255         int rc;
256         slap_mask_t mask = 0;
257         int ixop = opid;
258         AttrInfo *ai = NULL;
259
260         if ( opid == WT_INDEX_UPDATE_OP )
261                 ixop = SLAP_INDEX_ADD_OP;
262
263         if( type->sat_sup ) {
264                 /* recurse */
265                 rc = index_at_values( op, wc, NULL,
266                                                           type->sat_sup, tags,
267                                                           vals, id, opid );
268
269                 if( rc ) return rc;
270         }
271
272         /* If this type has no AD, we've never used it before */
273         if( type->sat_ad ) {
274                 ai = wt_attr_mask( op->o_bd->be_private, type->sat_ad );
275                 if ( ai ) {
276                         #ifdef LDAP_COMP_MATCH
277                         /* component indexing */
278                         if ( ai->ai_cr ) {
279                                 ComponentReference *cr;
280                                 for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
281                                         rc = indexer( op, wc, cr->cr_ad, &type->sat_cname,
282                                                                   cr->cr_nvals, id, ixop,
283                                                                   cr->cr_indexmask );
284                                 }
285                         }
286                         #endif
287                         ad = type->sat_ad;
288                         /* If we're updating the index, just set the new bits that aren't
289              * already in the old mask.
290              */
291                         if ( opid == WT_INDEX_UPDATE_OP )
292                                 mask = ai->ai_newmask & ~ai->ai_indexmask;
293                         else
294                                 /* For regular updates, if there is a newmask use it. Otherwise
295                                  * just use the old mask.
296                                  */
297                                 mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
298                         if( mask ) {
299                                 rc = indexer( op, wc, ad, &type->sat_cname,
300                                                           vals, id, ixop, mask );
301                                 if( rc ) return rc;
302                         }
303                 }
304         }
305
306         if( tags->bv_len ) {
307                 AttributeDescription *desc;
308
309                 desc = ad_find_tags( type, tags );
310                 if( desc ) {
311                         ai = wt_attr_mask( op->o_bd->be_private, desc );
312
313                         if( ai ) {
314                                 if ( opid == WT_INDEX_UPDATE_OP )
315                                         mask = ai->ai_newmask & ~ai->ai_indexmask;
316                                 else
317                                         mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
318                                 if ( mask ) {
319                                         rc = indexer( op, wc, desc, &desc->ad_cname,
320                                                                   vals, id, ixop, mask );
321
322                                         if( rc ) {
323                                                 return rc;
324                                         }
325                                 }
326                         }
327                 }
328         }
329
330         return LDAP_SUCCESS;
331 }
332
333 int wt_index_values(
334         Operation *op,
335         wt_ctx *wc,
336         AttributeDescription *desc,
337         BerVarray vals,
338         ID id,
339         int opid )
340 {
341         int rc;
342
343         /* Never index ID 0 */
344         if ( id == 0 )
345                 return 0;
346
347         rc = index_at_values( op, wc, desc,
348                                                   desc->ad_type, &desc->ad_tags,
349                                                   vals, id, opid );
350
351         return rc;
352 }
353
354 int
355 wt_index_entry( Operation *op, wt_ctx *wc, int opid, Entry *e )
356 {
357         int rc;
358         Attribute *ap = e->e_attrs;
359
360         if ( e->e_id == 0 )
361                 return 0;
362
363         Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
364                    opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
365                    (long) e->e_id, e->e_dn ? e->e_dn : "" );
366
367         for ( ; ap != NULL; ap = ap->a_next ) {
368                 rc = wt_index_values( op, wc, ap->a_desc,
369                                                           ap->a_nvals, e->e_id, opid );
370                 if( rc != LDAP_SUCCESS ) {
371                         Debug( LDAP_DEBUG_TRACE,
372                                    "<= index_entry_%s( %ld, \"%s\" ) failure\n",
373                                    opid == SLAP_INDEX_ADD_OP ? "add" : "del",
374                                    (long) e->e_id, e->e_dn );
375                         return rc;
376                 }
377         }
378
379         Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
380                    opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
381                    (long) e->e_id, e->e_dn ? e->e_dn : "" );
382         return 0;
383 }
384
385 /*
386  * Local variables:
387  * indent-tabs-mode: t
388  * tab-width: 4
389  * c-basic-offset: 4
390  * End:
391  */