/* OpenLDAP WiredTiger backend */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2002-2022 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was developed by HAMANO Tsukasa * based on back-bdb for inclusion in OpenLDAP Software. * WiredTiger is a product of MongoDB Inc. */ #include "portable.h" #include #include #include "back-wt.h" #include "slap-config.h" static char presence_keyval[] = {0,0}; static struct berval presence_key = BER_BVC(presence_keyval); AttrInfo *wt_index_mask( Backend *be, AttributeDescription *desc, struct berval *atname ) { AttributeType *at; AttrInfo *ai = wt_attr_mask( be->be_private, desc ); if( ai ) { *atname = desc->ad_cname; return ai; } /* If there is a tagging option, did we ever index the base * type? If so, check for mask, otherwise it's not there. */ if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) { /* has tagging option */ ai = wt_attr_mask( be->be_private, desc->ad_type->sat_ad ); if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOTAGS ) ) { *atname = desc->ad_type->sat_cname; return ai; } } /* see if supertype defined mask for its subtypes */ for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) { /* If no AD, we've never indexed this type */ if ( !at->sat_ad ) continue; ai = wt_attr_mask( be->be_private, at->sat_ad ); if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOSUBTYPES ) ) { *atname = at->sat_cname; return ai; } } return 0; } /* This function is only called when evaluating search filters. */ int wt_index_param( Backend *be, AttributeDescription *desc, int ftype, slap_mask_t *maskp, struct berval *prefixp ) { AttrInfo *ai; slap_mask_t mask, type = 0; ai = wt_index_mask( be, desc, prefixp ); if ( !ai ) { /* TODO: add monitor */ return LDAP_INAPPROPRIATE_MATCHING; } mask = ai->ai_indexmask; switch( ftype ) { case LDAP_FILTER_PRESENT: type = SLAP_INDEX_PRESENT; if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) { *prefixp = presence_key; *maskp = mask; return LDAP_SUCCESS; } break; case LDAP_FILTER_APPROX: type = SLAP_INDEX_APPROX; if ( desc->ad_type->sat_approx ) { if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) { *maskp = mask; return LDAP_SUCCESS; } break; } /* Use EQUALITY rule and index for approximate match */ /* fall thru */ case LDAP_FILTER_EQUALITY: type = SLAP_INDEX_EQUALITY; if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) { *maskp = mask; return LDAP_SUCCESS; } break; case LDAP_FILTER_SUBSTRINGS: type = SLAP_INDEX_SUBSTR; if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) { *maskp = mask; return LDAP_SUCCESS; } break; default: return LDAP_OTHER; } /* TODO: add monitor index */ return LDAP_INAPPROPRIATE_MATCHING; } static int indexer( Operation *op, wt_ctx *wc, AttributeDescription *ad, struct berval *atname, BerVarray vals, ID id, int opid, slap_mask_t mask ) { int rc = LDAP_SUCCESS, i; struct berval *keys; WT_CURSOR *cursor = NULL; assert( mask != 0 ); cursor = wt_index_open(wc, atname, 1); if( !cursor ) { Debug( LDAP_DEBUG_ANY, "indexer: open index cursor failed: %s\n", atname->bv_val ); goto done; } if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) { rc = wt_key_change( op->o_bd, cursor, &presence_key, id, opid ); if( rc ) { goto done; } } if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) { rc = ad->ad_type->sat_equality->smr_indexer( LDAP_FILTER_EQUALITY, mask, ad->ad_type->sat_syntax, ad->ad_type->sat_equality, atname, vals, &keys, op->o_tmpmemctx ); if( rc == LDAP_SUCCESS && keys != NULL ) { for( i=0; keys[i].bv_val != NULL; i++ ) { rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid ); if( rc ) { ber_bvarray_free_x( keys, op->o_tmpmemctx ); goto done; } } ber_bvarray_free_x( keys, op->o_tmpmemctx ); } rc = LDAP_SUCCESS; } if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) { rc = ad->ad_type->sat_approx->smr_indexer( LDAP_FILTER_APPROX, mask, ad->ad_type->sat_syntax, ad->ad_type->sat_approx, atname, vals, &keys, op->o_tmpmemctx ); if( rc == LDAP_SUCCESS && keys != NULL ) { for( i=0; keys[i].bv_val != NULL; i++ ) { rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid ); if( rc ) { ber_bvarray_free_x( keys, op->o_tmpmemctx ); goto done; } } ber_bvarray_free_x( keys, op->o_tmpmemctx ); } rc = LDAP_SUCCESS; } if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) { rc = ad->ad_type->sat_substr->smr_indexer( LDAP_FILTER_SUBSTRINGS, mask, ad->ad_type->sat_syntax, ad->ad_type->sat_substr, atname, vals, &keys, op->o_tmpmemctx ); if( rc == LDAP_SUCCESS && keys != NULL ) { for( i=0; keys[i].bv_val != NULL; i++ ) { rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid ); if( rc ) { ber_bvarray_free_x( keys, op->o_tmpmemctx ); goto done; } } ber_bvarray_free_x( keys, op->o_tmpmemctx ); } rc = LDAP_SUCCESS; } done: cursor->close(cursor); return rc; } static int index_at_values( Operation *op, wt_ctx *wc, AttributeDescription *ad, AttributeType *type, struct berval *tags, BerVarray vals, ID id, int opid ) { int rc = LDAP_SUCCESS; slap_mask_t mask = 0; int ixop = opid; AttrInfo *ai = NULL; if ( opid == WT_INDEX_UPDATE_OP ) ixop = SLAP_INDEX_ADD_OP; if( type->sat_sup ) { /* recurse */ rc = index_at_values( op, wc, NULL, type->sat_sup, tags, vals, id, opid ); if( rc ) return rc; } /* If this type has no AD, we've never used it before */ if( type->sat_ad ) { ai = wt_attr_mask( op->o_bd->be_private, type->sat_ad ); if ( ai ) { #ifdef LDAP_COMP_MATCH /* component indexing */ if ( ai->ai_cr ) { ComponentReference *cr; for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) { rc = indexer( op, wc, cr->cr_ad, &type->sat_cname, cr->cr_nvals, id, ixop, cr->cr_indexmask ); } } #endif ad = type->sat_ad; /* If we're updating the index, just set the new bits that aren't * already in the old mask. */ if ( opid == WT_INDEX_UPDATE_OP ) mask = ai->ai_newmask & ~ai->ai_indexmask; else /* For regular updates, if there is a newmask use it. Otherwise * just use the old mask. */ mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask; if( mask ) { rc = indexer( op, wc, ad, &type->sat_cname, vals, id, ixop, mask ); if( rc ) return rc; } } } if( tags->bv_len ) { AttributeDescription *desc; desc = ad_find_tags( type, tags ); if( desc ) { ai = wt_attr_mask( op->o_bd->be_private, desc ); if( ai ) { if ( opid == WT_INDEX_UPDATE_OP ) mask = ai->ai_newmask & ~ai->ai_indexmask; else mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask; if ( mask ) { rc = indexer( op, wc, desc, &desc->ad_cname, vals, id, ixop, mask ); if( rc ) { return rc; } } } } } return LDAP_SUCCESS; } int wt_index_values( Operation *op, wt_ctx *wc, AttributeDescription *desc, BerVarray vals, ID id, int opid ) { int rc; /* Never index ID 0 */ if ( id == 0 ) return 0; rc = index_at_values( op, wc, desc, desc->ad_type, &desc->ad_tags, vals, id, opid ); return rc; } int wt_index_entry( Operation *op, wt_ctx *wc, int opid, Entry *e ) { int rc; Attribute *ap = e->e_attrs; if ( e->e_id == 0 ) return 0; Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n", opid == SLAP_INDEX_DELETE_OP ? "del" : "add", (long) e->e_id, e->e_dn ? e->e_dn : "" ); for ( ; ap != NULL; ap = ap->a_next ) { rc = wt_index_values( op, wc, ap->a_desc, ap->a_nvals, e->e_id, opid ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) failure\n", opid == SLAP_INDEX_ADD_OP ? "add" : "del", (long) e->e_id, e->e_dn ); return rc; } } Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n", opid == SLAP_INDEX_DELETE_OP ? "del" : "add", (long) e->e_id, e->e_dn ? e->e_dn : "" ); return 0; } WT_CURSOR * wt_index_open(wt_ctx *wc, struct berval *name, int create) { WT_CURSOR *cursor = NULL; WT_SESSION *session = wc->session; char uri[1024]; int rc; snprintf(uri, sizeof(uri), "table:%s", name->bv_val); rc = session->open_cursor(session, uri, NULL, "overwrite=false", &cursor); if (rc == ENOENT && create) { rc = session->create(session, uri, "key_format=uQ," "value_format=x," "columns=(key, id, none)"); if( rc ) { Debug( LDAP_DEBUG_ANY, "wt_index_open: table \"%s\": " "cannot create index table: %s (%d)\n", uri, wiredtiger_strerror(rc), rc); return NULL; } rc = session->open_cursor(session, uri, NULL, "overwrite=false", &cursor); } if ( rc ) { Debug( LDAP_DEBUG_ANY, "wt_index_open: table \"%s\": " ": open cursor failed: %s (%d)\n", uri, wiredtiger_strerror(rc), rc); return NULL; } return cursor; } /* * Local variables: * indent-tabs-mode: t * tab-width: 4 * c-basic-offset: 4 * End: */