From 5de908e7e18bbd992f0dec5def4eee3c438fe361 Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@openldap.org>
Date: Thu, 21 Apr 2005 19:04:31 +0000
Subject: [PATCH] Dynamic indexing support

---
 servers/slapd/back-bdb/attr.c        | 107 ++++++++--------
 servers/slapd/back-bdb/back-bdb.h    |  21 +++-
 servers/slapd/back-bdb/config.c      | 177 +++++++++++++++++++++++++--
 servers/slapd/back-bdb/filterindex.c |   8 +-
 servers/slapd/back-bdb/index.c       | 127 +++++++++++--------
 servers/slapd/back-bdb/init.c        |   8 +-
 servers/slapd/back-bdb/proto-bdb.h   |  18 +--
 7 files changed, 330 insertions(+), 136 deletions(-)

diff --git a/servers/slapd/back-bdb/attr.c b/servers/slapd/back-bdb/attr.c
index 42b2bc3c26..395455318b 100644
--- a/servers/slapd/back-bdb/attr.c
+++ b/servers/slapd/back-bdb/attr.c
@@ -25,14 +25,6 @@
 #include "back-bdb.h"
 #include "lutil.h"
 
-/* for the cache of attribute information (which are indexed, etc.) */
-typedef struct bdb_attrinfo {
-	AttributeDescription *ai_desc; /* attribute description cn;lang-en */
-	slap_mask_t ai_indexmask;	/* how the attr is indexed	*/
-#ifdef LDAP_COMP_MATCH
-	ComponentReference* ai_cr; /*component indexing*/
-#endif
-} AttrInfo;
 
 static int
 ainfo_type_cmp(
@@ -55,50 +47,13 @@ ainfo_cmp(
 	return SLAP_PTRCMP(a->ai_desc, b->ai_desc);
 }
 
-#ifdef LDAP_COMP_MATCH
-void
-bdb_attr_comp_ref(
-	struct bdb_info *bdb,
-	AttributeDescription *desc,
-	ComponentReference** cr )
-{
-	AttrInfo	*a;
-
-	a = (AttrInfo *) avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
-	
-	*cr = a != NULL ? a->ai_cr : 0 ;
-}
-void
-bdb_attr_mask_cr(
-	struct bdb_info *bdb,
-	AttributeDescription *desc,
-	slap_mask_t *indexmask,
-	ComponentReference** cr )
-{
-	AttrInfo	*a;
-
-	a = (AttrInfo *) avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
-	if ( a ) {
-		*indexmask = a->ai_indexmask;
-		*cr = a->ai_cr;
-	} else {
-		*indexmask = 0;
-		*cr = NULL;
-	}
-}
-#endif
-
-void
+AttrInfo *
 bdb_attr_mask(
 	struct bdb_info	*bdb,
-	AttributeDescription *desc,
-	slap_mask_t *indexmask )
+	AttributeDescription *desc )
 {
-	AttrInfo	*a;
 
-	a = (AttrInfo *) avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
-	
-	*indexmask = a != NULL ? a->ai_indexmask : 0;
+	return avl_find( bdb->bi_attrs, desc, ainfo_type_cmp );
 }
 
 int
@@ -254,7 +209,15 @@ bdb_attr_index_config(
 			ad->ad_cname.bv_val, mask, 0 ); 
 
 		a->ai_desc = ad;
-		a->ai_indexmask = mask;
+
+		if ( bdb->bi_flags & BDB_IS_OPEN ) {
+			a->ai_indexmask = 0;
+			a->ai_newmask = mask;
+		} else {
+			a->ai_indexmask = mask;
+			a->ai_newmask = 0;
+		}
+
 #ifdef LDAP_COMP_MATCH
 		if ( cr ) {
 			a_cr = avl_find( bdb->bi_attrs, ad, ainfo_type_cmp );
@@ -283,6 +246,17 @@ bdb_attr_index_config(
 		                 ainfo_cmp, avl_dup_error );
 
 		if( rc ) {
+			if ( bdb->bi_flags & BDB_IS_OPEN ) {
+				AttrInfo *b = avl_find( bdb->bi_attrs, ad, ainfo_type_cmp );
+				/* If we were editing this attr, reset it */
+				b->ai_indexmask &= ~BDB_INDEX_DELETING;
+				/* If this is leftover from a previous add, commit it */
+				if ( b->ai_newmask )
+					b->ai_indexmask = b->ai_newmask;
+				b->ai_newmask = a->ai_newmask;
+				ch_free( a );
+				continue;
+			}
 			fprintf( stderr, "%s: line %d: duplicate index definition "
 				"for attr \"%s\" (ignored)\n",
 				fname, lineno, attrs[i] );
@@ -353,3 +327,38 @@ void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad )
 	if ( ai )
 		bdb_attrinfo_free( ai );
 }
+
+/* Get a list of AttrInfo's to delete */
+
+typedef struct Alist {
+	struct Alist *next;
+	AttrInfo *ptr;
+} Alist;
+
+static int
+bdb_attrinfo_flush( void *v1, void *arg )
+{
+	AttrInfo *ai = v1;
+
+	if ( ai->ai_indexmask & BDB_INDEX_DELETING ) {
+		Alist **al = arg;
+		Alist *a = ch_malloc( sizeof( Alist ));
+		a->ptr = ai;
+		a->next = *al;
+		*al = a;
+	}
+	return 0;
+}
+
+void bdb_attr_flush( struct bdb_info *bdb )
+{
+	Alist *al = NULL, *a2;
+
+	avl_apply( bdb->bi_attrs, bdb_attrinfo_flush, &al, -1, AVL_INORDER );
+
+	while (( a2 = al )) {
+		al = al->next;
+		avl_delete( &bdb->bi_attrs, a2->ptr, ainfo_cmp );
+		ch_free( a2 );
+	}
+}
diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h
index 6e7b35dca6..cd42903b7f 100644
--- a/servers/slapd/back-bdb/back-bdb.h
+++ b/servers/slapd/back-bdb/back-bdb.h
@@ -187,8 +187,11 @@ struct bdb_info {
 	alock_info_t	bi_alock_info;
 	char		*bi_db_config_path;
 	BerVarray	bi_db_config;
-	int		bi_db_is_open;
-	int		bi_db_has_config;
+	int		bi_flags;
+#define	BDB_IS_OPEN		0x01
+#define	BDB_HAS_CONFIG	0x02
+#define	BDB_UPD_CONFIG	0x04
+#define	BDB_DEL_INDEX	0x08
 };
 
 #define bi_id2entry	bi_databases[BDB_ID2ENTRY]
@@ -272,6 +275,20 @@ struct bdb_op_info {
 
 LDAP_END_DECL
 
+/* for the cache of attribute information (which are indexed, etc.) */
+typedef struct bdb_attrinfo {
+	AttributeDescription *ai_desc; /* attribute description cn;lang-en */
+	slap_mask_t ai_indexmask;	/* how the attr is indexed	*/
+	slap_mask_t ai_newmask;	/* new settings to replace old mask */
+#ifdef LDAP_COMP_MATCH
+	ComponentReference* ai_cr; /*component indexing*/
+#endif
+} AttrInfo;
+
+/* These flags must not clash with SLAP_INDEX flags or ops in slap.h! */
+#define	BDB_INDEX_DELETING	0x8000U	/* index is being modified */
+#define	BDB_INDEX_UPDATE_OP	0x03	/* performing an index update */
+
 #include "proto-bdb.h"
 
 #endif /* _BACK_BDB_H_ */
diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c
index 87c2e884fb..91dcad1074 100644
--- a/servers/slapd/back-bdb/config.c
+++ b/servers/slapd/back-bdb/config.c
@@ -24,6 +24,7 @@
 #include "config.h"
 
 #include "lutil.h"
+#include "ldap_rq.h"
 
 #ifdef DB_DIRTY_READ
 #	define	SLAP_BDB_ALLOW_DIRTY_READ
@@ -86,6 +87,7 @@ static ConfigTable bdbcfg[] = {
 	{ "index", "attr> <[pres,eq,approx,sub]", 2, 3, 0, ARG_MAGIC|BDB_INDEX,
 		bdb_cf_gen, "( OLcfgDbAt:0.2 NAME 'olcDbIndex' "
 		"DESC 'Attribute index parameters' "
+		"EQUALITY caseIgnoreMatch "
 		"SYNTAX OMsDirectoryString )", NULL, NULL },
 	{ "linearindex", NULL, 1, 2, 0, ARG_ON_OFF|ARG_OFFSET,
 		(void *)offsetof(struct bdb_info, bi_linear_index), 
@@ -147,6 +149,141 @@ static slap_verbmasks bdb_lockd[] = {
 	{ BER_BVNULL, 0 }
 };
 
+/* reindex entries on the fly */
+static void *
+bdb_online_index( void *ctx, void *arg )
+{
+	struct re_s *rtask = arg;
+	BackendDB *be = rtask->arg;
+	struct bdb_info *bdb = be->be_private;
+
+	Connection conn = {0};
+	char opbuf[OPERATION_BUFFER_SIZE];
+	Operation *op = (Operation *)opbuf;
+
+	DBC *curs;
+	DBT key, data;
+	DB_TXN *txn;
+	DB_LOCK lock;
+	u_int32_t locker;
+	ID id, nid;
+	EntryInfo *ei;
+	int rc, getnext = 1;
+
+	connection_fake_init( &conn, op, ctx );
+
+	op->o_bd = be;
+
+	DBTzero( &key );
+	DBTzero( &data );
+	
+	id = 1;
+	key.data = &nid;
+	key.size = key.ulen = sizeof(ID);
+	key.flags = DB_DBT_USERMEM;
+
+	data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
+	data.dlen = data.ulen = 0;
+
+	while ( 1 ) {
+		rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &txn, bdb->bi_db_opflags );
+		if ( rc ) 
+			break;
+		locker = TXN_ID( txn );
+		if ( getnext ) {
+			getnext = 0;
+			BDB_ID2DISK( id, &nid );
+			rc = bdb->bi_id2entry->bdi_db->cursor(
+				bdb->bi_id2entry->bdi_db, txn, &curs, bdb->bi_db_opflags );
+			if ( rc ) {
+				TXN_ABORT( txn );
+				break;
+			}
+			rc = curs->c_get( curs, &key, &data, DB_SET_RANGE );
+			curs->c_close( curs );
+			if ( rc ) {
+				TXN_ABORT( txn );
+				if ( rc == DB_NOTFOUND )
+					rc = 0;
+				if ( rc == DB_LOCK_DEADLOCK ) {
+					ldap_pvt_thread_yield();
+					continue;
+				}
+				break;
+			}
+			BDB_DISK2ID( &nid, &id );
+		}
+
+		ei = NULL;
+		rc = bdb_cache_find_id( op, txn, id, &ei, 0, locker, &lock );
+		if ( rc ) {
+			TXN_ABORT( txn );
+			if ( rc == DB_LOCK_DEADLOCK ) {
+				ldap_pvt_thread_yield();
+				continue;
+			}
+			if ( rc == DB_NOTFOUND ) {
+				id++
+				getnext = 1;
+				continue;
+			}
+			break;
+		}
+		if ( ei->bei_e ) {
+			rc = bdb_index_entry( op, txn, BDB_INDEX_UPDATE_OP, ei->bei_e );
+			if ( rc == DB_LOCK_DEADLOCK ) {
+				TXN_ABORT( txn );
+				ldap_pvt_thread_yield();
+				continue;
+			}
+			if ( rc == 0 ) {
+				rc = TXN_COMMIT( txn, 0 );
+				txn = NULL;
+			}
+			if ( rc )
+				break;
+		}
+		id++;
+		getnext = 1;
+	}
+out:
+	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+	ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
+	ldap_pvt_runqueue_remove( &slapd_rq, rtask );
+	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+	return NULL;
+}
+
+/* Cleanup loose ends after Modify completes */
+static int
+bdb_cf_cleanup( ConfigArgs *c )
+{
+	struct bdb_info *bdb = c->be->be_private;
+
+	if ( bdb->bi_flags & BDB_UPD_CONFIG ) {
+		if ( bdb->bi_db_config ) {
+			int i;
+			FILE *f = fopen( bdb->bi_db_config_path, "w" );
+			if ( f ) {
+				for (i=0; bdb->bi_db_config[i].bv_val; i++)
+					fprintf( f, "%s\n", bdb->bi_db_config[i].bv_val );
+				fclose( f );
+			}
+		} else {
+			unlink( bdb->bi_db_config_path );
+		}
+		bdb->bi_flags ^= BDB_UPD_CONFIG;
+	}
+
+	if ( bdb->bi_flags & BDB_DEL_INDEX ) {
+		bdb_attr_flush( bdb );
+		bdb->bi_flags ^= BDB_DEL_INDEX;
+	}
+
+	return 0;
+}
+
 static int
 bdb_cf_gen(ConfigArgs *c)
 {
@@ -234,8 +371,17 @@ bdb_cf_gen(ConfigArgs *c)
 			bdb->bi_txn_cp = 0;
 			break;
 		case BDB_CONFIG:
-			rc = 1;
-			/* FIXME: delete values or the whole file? */
+			if ( c->valx < 0 ) {
+				ber_bvarray_free( bdb->bi_db_config );
+				bdb->bi_db_config = NULL;
+			} else {
+				int i = c->valx;
+				ch_free( bdb->bi_db_config[i].bv_val );
+				for (; bdb->bi_db_config[i].bv_val; i++)
+					bdb->bi_db_config[i] = bdb->bi_db_config[i+1];
+			}
+			bdb->bi_flags |= BDB_UPD_CONFIG;
+			c->cleanup = bdb_cf_cleanup;
 			break;
 		case BDB_DIRECTORY:
 			rc = 1;
@@ -252,12 +398,16 @@ bdb_cf_gen(ConfigArgs *c)
 			for (ptr = c->line; !isspace( *ptr ); ptr++);
 			bv.bv_val = c->line;
 			bv.bv_len = ptr - bv.bv_val;
-			if ( ber_bvmatch( &bv, &defbv )) {
+			if ( bvmatch( &bv, &def )) {
 				bdb->bi_defaultmask = 0;
 			} else {
 				slap_bv2ad( &bv, &ad, &text );
-				if ( ad )
-					bdb_attr_index_free( bdb, ad );
+				if ( ad ) {
+					AttrInfo *ai = bdb_attr_mask( bdb, ad );
+					ai->ai_indexmask |= BDB_INDEX_DELETING;
+					bdb->bi_flags |= BDB_DEL_INDEX;
+					c->cleanup = bdb_cf_cleanup;
+				}
 			}
 			}
 			break;
@@ -278,14 +428,17 @@ bdb_cf_gen(ConfigArgs *c)
 		while (!isspace(*ptr)) ptr++;
 		while (isspace(*ptr)) ptr++;
 		
+		if ( bdb->bi_flags & BDB_IS_OPEN ) {
+			bdb->bi_flags |= BDB_UPD_CONFIG;
+			c->cleanup = bdb_cf_cleanup;
+		} else {
 		/* If we're just starting up...
 		 */
-		if ( !bdb->bi_db_is_open ) {
 			FILE *f;
 			/* If a DB_CONFIG file exists, or we don't know the path
 			 * to the DB_CONFIG file, ignore these directives
 			 */
-			if ( bdb->bi_db_has_config || !bdb->bi_db_config_path )
+			if (( bdb->bi_flags & BDB_HAS_CONFIG ) || !bdb->bi_db_config_path )
 				break;
 			f = fopen( bdb->bi_db_config_path, "a" );
 			if ( f ) {
@@ -314,7 +467,7 @@ bdb_cf_gen(ConfigArgs *c)
 
 		f = fopen( bdb->bi_db_config_path, "r" );
 		if ( f ) {
-			bdb->bi_db_has_config = 1;
+			bdb->bi_flags |= BDB_HAS_CONFIG;
 			fclose(f);
 		}
 		}
@@ -325,7 +478,7 @@ bdb_cf_gen(ConfigArgs *c)
 			bdb->bi_dbenv_xflags |= DB_TXN_NOSYNC;
 		else
 			bdb->bi_dbenv_xflags &= ~DB_TXN_NOSYNC;
-		if ( bdb->bi_db_is_open ) {
+		if ( bdb->bi_flags & BDB_IS_OPEN ) {
 			bdb->bi_dbenv->set_flags( bdb->bi_dbenv, DB_TXN_NOSYNC,
 				c->value_int );
 		}
@@ -336,8 +489,10 @@ bdb_cf_gen(ConfigArgs *c)
 			c->argc - 1, &c->argv[1] );
 
 		if( rc != LDAP_SUCCESS ) return 1;
-		/* FIXME: must run slapindex on the new attributes */
-		if ( bdb->bi_db_is_open ) {
+		if ( bdb->bi_flags & BDB_IS_OPEN ) {
+			/* Start the task as soon as we finish here */
+			ldap_pvt_runqueue_insert( &slapd_rq, 60,
+				bdb_online_index, c->be );
 		}
 		break;
 
diff --git a/servers/slapd/back-bdb/filterindex.c b/servers/slapd/back-bdb/filterindex.c
index ea997d1b35..b6bc5328b0 100644
--- a/servers/slapd/back-bdb/filterindex.c
+++ b/servers/slapd/back-bdb/filterindex.c
@@ -297,12 +297,16 @@ comp_equality_candidates (
         MatchingRule *mr = mra->ma_rule;
         Syntax *sat_syntax;
 	ComponentReference* cr_list, *cr;
+	AttrInfo *ai;
 
         BDB_IDL_ALL( bdb, ids );
 
-	bdb_attr_comp_ref ( op->o_bd->be_private, mra->ma_desc, &cr_list );
-	if( !cr_list || !ca->ca_comp_ref )
+	if ( !ca->ca_comp_ref )
 		return 0;
+
+	ai = bdb_attr_mask( op->o_bd->be_private, mra->ma_desc );
+	if( ai )
+		cr_list = ai->ai_cr;
 	/* find a component reference to be indexed */
 	sat_syntax = ca->ca_ma_rule->smr_syntax;
 	for ( cr = cr_list ; cr ; cr = cr->cr_next ) {
diff --git a/servers/slapd/back-bdb/index.c b/servers/slapd/back-bdb/index.c
index 1dd494c375..ffa2f27ce0 100644
--- a/servers/slapd/back-bdb/index.c
+++ b/servers/slapd/back-bdb/index.c
@@ -28,19 +28,17 @@
 static char presence_keyval[LUTIL_HASH_BYTES] = {0,0,0,1};
 static struct berval presence_key = {LUTIL_HASH_BYTES, presence_keyval};
 
-static slap_mask_t index_mask(
+static AttrInfo *index_mask(
 	Backend *be,
 	AttributeDescription *desc,
 	struct berval *atname )
 {
 	AttributeType *at;
-	slap_mask_t mask = 0;
-
-	bdb_attr_mask( be->be_private, desc, &mask );
+	AttrInfo *ai = bdb_attr_mask( be->be_private, desc );
 
-	if( mask ) {
+	if( ai ) {
 		*atname = desc->ad_cname;
-		return mask;
+		return ai;
 	}
 
 	/* If there is a tagging option, did we ever index the base
@@ -48,11 +46,11 @@ static slap_mask_t index_mask(
 	 */
 	if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) {
 		/* has tagging option */
-		bdb_attr_mask( be->be_private, desc->ad_type->sat_ad, &mask );
+		ai = bdb_attr_mask( be->be_private, desc->ad_type->sat_ad );
 
-		if ( mask && ( mask ^ SLAP_INDEX_NOTAGS ) ) {
+		if ( ai && ( ai->ai_indexmask ^ SLAP_INDEX_NOTAGS ) ) {
 			*atname = desc->ad_type->sat_cname;
-			return mask;
+			return ai;
 		}
 	}
 
@@ -61,11 +59,11 @@ static slap_mask_t index_mask(
 		/* If no AD, we've never indexed this type */
 		if ( !at->sat_ad ) continue;
 
-		bdb_attr_mask( be->be_private, at->sat_ad, &mask );
+		ai = bdb_attr_mask( be->be_private, at->sat_ad );
 
-		if ( mask && ( mask ^ SLAP_INDEX_NOSUBTYPES ) ) {
+		if ( ai && ( ai->ai_indexmask ^ SLAP_INDEX_NOSUBTYPES ) ) {
 			*atname = at->sat_cname;
-			return mask;
+			return ai;
 		}
 	}
 
@@ -76,18 +74,19 @@ int bdb_index_is_indexed(
 	Backend *be,
 	AttributeDescription *desc )
 {
-	slap_mask_t mask;
+	AttrInfo *ai;
 	struct berval prefix;
 
-	mask = index_mask( be, desc, &prefix );
+	ai = index_mask( be, desc, &prefix );
 
-	if( mask == 0 ) {
+	if( !ai )
 		return LDAP_INAPPROPRIATE_MATCHING;
-	}
 
 	return LDAP_SUCCESS;
 }
 
+/* This function is only called when evaluating search filters.
+ */
 int bdb_index_param(
 	Backend *be,
 	AttributeDescription *desc,
@@ -96,15 +95,17 @@ int bdb_index_param(
 	slap_mask_t *maskp,
 	struct berval *prefixp )
 {
+	AttrInfo *ai;
 	int rc;
 	slap_mask_t mask;
 	DB *db;
 
-	mask = index_mask( be, desc, prefixp );
+	ai = index_mask( be, desc, prefixp );
 
-	if( mask == 0 ) {
+	if( !ai ) {
 		return LDAP_INAPPROPRIATE_MATCHING;
 	}
+	mask = ai->ai_indexmask;
 
 	rc = bdb_db_cache( be, prefixp->bv_val, &db );
 
@@ -268,6 +269,11 @@ static int index_at_values(
 {
 	int rc;
 	slap_mask_t mask = 0;
+	int ixop = opid;
+	AttrInfo *ai = NULL;
+
+	if ( opid == BDB_INDEX_UPDATE_OP )
+		ixop = SLAP_INDEX_ADD_OP;
 
 	if( type->sat_sup ) {
 		/* recurse */
@@ -280,49 +286,59 @@ static int index_at_values(
 
 	/* If this type has no AD, we've never used it before */
 	if( type->sat_ad ) {
+		ai = bdb_attr_mask( op->o_bd->be_private, type->sat_ad );
+		if ( ai ) {
 #ifdef LDAP_COMP_MATCH
-		/* component indexing */
-		ComponentReference* cr_list, *cr;
-
-		bdb_attr_mask_cr( op->o_bd->be_private, type->sat_ad, &mask, &cr_list );
-		if ( cr_list ) {
-			for( cr = cr_list ; cr ; cr = cr->cr_next ) {
-				rc = indexer( op, txn, cr->cr_ad, &type->sat_cname,
-					cr->cr_nvals, id, opid,
-					cr->cr_indexmask );
+			/* component indexing */
+			if ( ai->ai_cr ) {
+				ComponentReference *cr;
+				for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
+					rc = indexer( op, txn, cr->cr_ad, &type->sat_cname,
+						cr->cr_nvals, id, opid,
+						cr->cr_indexmask );
+				}
 			}
-		}
-#else
-		bdb_attr_mask( op->o_bd->be_private, type->sat_ad, &mask );
 #endif
-		ad = type->sat_ad;
-	}
-
-	if( mask ) {
-		rc = indexer( op, txn, ad, &type->sat_cname,
-			vals, id, opid,
-			mask );
-
-		if( rc ) return rc;
+			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 == BDB_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, txn, ad, &type->sat_cname,
+					vals, id, ixop, mask );
+
+				if( rc ) return rc;
+			}
+		}
 	}
 
 	if( tags->bv_len ) {
 		AttributeDescription *desc;
 
-		mask = 0;
-
 		desc = ad_find_tags( type, tags );
 		if( desc ) {
-			bdb_attr_mask( op->o_bd->be_private, desc, &mask );
-		}
-
-		if( mask ) {
-			rc = indexer( op, txn, desc, &desc->ad_cname,
-				vals, id, opid,
-				mask );
-
-			if( rc ) {
-				return rc;
+			ai = bdb_attr_mask( op->o_bd->be_private, desc );
+
+			if( ai ) {
+				if ( opid == BDB_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, txn, desc, &desc->ad_cname,
+						vals, id, ixop, mask );
+
+					if( rc ) {
+						return rc;
+					}
+				}
 			}
 		}
 	}
@@ -373,14 +389,17 @@ bdb_index_entry(
 #endif
 
 	Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
-		opid == SLAP_INDEX_ADD_OP ? "add" : "del",
+		opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
 		(long) e->e_id, e->e_dn );
 
 	/* add each attribute to the indexes */
 	for ( ; ap != NULL; ap = ap->a_next ) {
 #ifdef LDAP_COMP_MATCH
+		AttrInfo *ai;
 		/* see if attribute has components to be indexed */
-		bdb_attr_comp_ref( op->o_bd->be_private, ap->a_desc->ad_type->sat_ad, &cr_list );
+		ai = bdb_attr_mask( op->o_bd->be_private, ap->a_desc->ad_type->sat_ad );
+		if ( ai ) cr_list = ai->ai_cr;
+		else cr_list = NULL;
 		if ( attr_converter && cr_list ) {
 			syn = ap->a_desc->ad_type->sat_syntax;
 			ap->a_comp_data = op->o_tmpalloc( sizeof( ComponentData ), op->o_tmpmemctx );
@@ -443,7 +462,7 @@ bdb_index_entry(
 	}
 
 	Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
-		opid == SLAP_INDEX_ADD_OP ? "add" : "del",
+		opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
 		(long) e->e_id, e->e_dn );
 
 	return LDAP_SUCCESS;
diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c
index fb2af4d1db..a7260399ad 100644
--- a/servers/slapd/back-bdb/init.c
+++ b/servers/slapd/back-bdb/init.c
@@ -546,7 +546,7 @@ bdb_db_open( BackendDB *be )
 		ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
 	}
 
-	if ( slapMode & SLAP_SERVER_MODE && bdb->bi_db_has_config ) {
+	if (( slapMode&SLAP_SERVER_MODE ) && ( bdb->bi_flags&BDB_HAS_CONFIG )) {
 		char	buf[SLAP_TEXT_BUFLEN];
 		FILE *f = fopen( bdb->bi_db_config_path, "r" );
 		struct berval bv;
@@ -568,11 +568,11 @@ bdb_db_open( BackendDB *be )
 			fclose( f );
 		} else {
 			/* Eh? It disappeared between config and open?? */
-			bdb->bi_db_has_config = 0;
+			bdb->bi_flags &= ~BDB_HAS_CONFIG;
 		}
 
 	}
-	bdb->bi_db_is_open = 1;
+	bdb->bi_flags |= BDB_IS_OPEN;
 
 	return 0;
 }
@@ -585,7 +585,7 @@ bdb_db_close( BackendDB *be )
 	struct bdb_db_info *db;
 	bdb_idl_cache_entry_t *entry, *next_entry;
 
-	bdb->bi_db_is_open = 0;
+	bdb->bi_flags &= ~BDB_IS_OPEN;
 
 	ber_bvarray_free( bdb->bi_db_config );
 
diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h
index 99716d2079..7d3d49b7d3 100644
--- a/servers/slapd/back-bdb/proto-bdb.h
+++ b/servers/slapd/back-bdb/proto-bdb.h
@@ -31,26 +31,16 @@ LDAP_BEGIN_DECL
  */
 
 #define bdb_attr_mask				BDB_SYMBOL(attr_mask)
+#define bdb_attr_flush				BDB_SYMBOL(attr_flush)
 #define bdb_attr_index_config		BDB_SYMBOL(attr_index_config)
 #define bdb_attr_index_destroy		BDB_SYMBOL(attr_index_destroy)
 #define bdb_attr_index_free			BDB_SYMBOL(attr_index_free)
 #define bdb_attr_index_unparse		BDB_SYMBOL(attr_index_unparse)
 
-#ifdef LDAP_COMP_MATCH
-#define bdb_attr_comp_ref			BDB_SYMBOL(attr_comp_ref)
-#define bdb_attr_mask_cr			BDB_SYMBOL(attr_mask_cr)
-void bdb_attr_comp_ref( struct bdb_info *bdb,
-	AttributeDescription *desc,
-	ComponentReference **cr );
-void bdb_attr_mask_cr( struct bdb_info *bdb,
-	AttributeDescription *desc,
-	slap_mask_t *indexmask,
-	ComponentReference **cr );
-#endif
+AttrInfo *bdb_attr_mask( struct bdb_info *bdb,
+	AttributeDescription *desc );
 
-void bdb_attr_mask( struct bdb_info *bdb,
-	AttributeDescription *desc,
-	slap_mask_t *indexmask );
+void bdb_attr_flush( struct bdb_info *bdb );
 
 int bdb_attr_index_config LDAP_P(( struct bdb_info *bdb,
 	const char *fname, int lineno,
-- 
GitLab