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