#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(
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
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 );
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] );
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 );
+ }
+}
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]
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_ */
#include "config.h"
#include "lutil.h"
+#include "ldap_rq.h"
#ifdef DB_DIRTY_READ
# define SLAP_BDB_ALLOW_DIRTY_READ
{ "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),
{ 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)
{
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;
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;
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 ) {
f = fopen( bdb->bi_db_config_path, "r" );
if ( f ) {
- bdb->bi_db_has_config = 1;
+ bdb->bi_flags |= BDB_HAS_CONFIG;
fclose(f);
}
}
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 );
}
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;
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 ) {
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
*/
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;
}
}
/* 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;
}
}
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,
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 );
{
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 */
/* 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;
+ }
+ }
}
}
}
#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 );
}
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;
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;
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;
}
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 );
*/
#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,