static char *rcsid
= "$Header: /f/osi/dsap/common/RCS/turbo_index.c,v 7.1 91/02/22 09:20:38 mrose Interim $";
* $Header: /f/osi/dsap/common/RCS/turbo_index.c,v 7.1 91/02/22 09:20:38 mrose Interim $
* $Log: turbo_index.c,v $
* Revision 7.1 91/02/22 09:20:38 mrose
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
#include "quipu/config.h"
AttributeType
*turbo_index_types
; /* array of attributes to optimize */
int turbo_index_num
; /* number of attributes to optimize */
Avlnode
*subtree_index
; /* array of subtree indexes */
Avlnode
*sibling_index
; /* array of sibling indexes */
int optimized_only
; /* only allow indexed searches */
return( AttrV_cmp( (AttributeValue
) a
->in_value
,
(AttributeValue
) b
->in_value
) );
static sindex_cmp( a
, b
)
return( strcmp( (char *) a
->in_value
, (char *) b
->in_value
) );
index_soundex_cmp( code
, node
)
return( strcmp( code
, (char *) node
->in_value
) );
index_soundex_prefix( code
, node
, len
)
return( strncmp( code
, (char *) node
->in_value
, len
) );
substring_prefix_cmp( val
, node
, len
)
return(strncmp((char *) val
->av_struct
,
(char *) (((AttributeValue
) node
->in_value
)->av_struct
), len
));
substring_prefix_case_cmp( val
, node
, len
)
return(lexnequ((char *) val
->av_struct
,
(char *) (((AttributeValue
) node
->in_value
)->av_struct
), len
));
return( AttrV_cmp( av
, (AttributeValue
) node
->in_value
) );
static index_dup( node
, dup
)
/* check for duplicates */
for ( i
= 0; i
< node
->in_num
; i
++ ) {
if ( node
->in_entries
[ i
] == dup
->in_entries
[ 0 ] )
if (node
->in_entries
[i
] > dup
->in_entries
[0])
node
->in_entries
= (struct entry
**) realloc( (char *)node
->in_entries
,
(unsigned) (sizeof(struct entry
*) * (node
->in_num
+ 1) ));
tmp1
= dup
->in_entries
[0];
for (j
= i
; j
< node
->in_num
; j
++) {
tmp2
= node
->in_entries
[j
];
node
->in_entries
[j
] = tmp1
;
static indexav_free( node
)
AttrV_free( (AttributeValue
) node
->in_value
);
free( (char *) node
->in_entries
);
static soundex_free( node
)
free( (char *) node
->in_value
);
free( (char *) node
->in_entries
);
static index_free( pindex
)
(void) avl_free( pindex
->i_root
, indexav_free
);
(void) avl_free( pindex
->i_sroot
, soundex_free
);
return( dn_order_cmp( a
->i_dn
, b
->i_dn
) );
return( dn_order_cmp( a
, b
->i_dn
) );
* siblings - return 1 if a and b are siblings, 0 otherwise
for ( ; a
&& b
; a
= a
->dn_parent
, b
= b
->dn_parent
) {
if ( dn_cmp( a
, b
) == NOTOK
) {
if ( a
->dn_parent
== NULLDN
&& b
->dn_parent
== NULLDN
)
if ( a
!= NULLDN
|| b
!= NULLDN
)
* prefix - returns the following:
* -1 => a is a prefix of b
* 1 => b is a prefix of a
* 2 => neither a nor b is a prefix of the other
for ( ; a
&& b
; a
= a
->dn_parent
, b
= b
->dn_parent
)
if ( dn_comp_cmp( a
, b
) == NOTOK
)
return( 2 ); /* neither is prefix */
if ( a
== NULLDN
&& b
== NULLDN
)
return( 0 ); /* they are equal */
return( -1 ); /* a is a prefix of b */
return( 1 ); /* b is a prefix of a */
static Index
*new_index( dn
)
pindex
= (Index
*) malloc( (unsigned) (sizeof(Index
) * turbo_index_num
));
for ( i
= 0; i
< turbo_index_num
; i
++ ) {
pindex
[ i
].i_attr
= turbo_index_types
[ i
];
pindex
[ i
].i_scount
= 0;
pindex
[ i
].i_root
= NULLAVL
;
pindex
[ i
].i_sroot
= NULLAVL
;
pindex
[ i
].i_nonleafkids
= (struct entry
**) 0;
pindex
[ i
].i_nonlocalaliases
= (struct entry
**) 0;
pindex
[ i
].i_dn
= dn_cpy( dn
);
static print_soundex_node( n
, ps
)
(void) printf( "\t(%s)\n",n
->in_value
);
for ( i
= 0; i
< n
->in_num
; i
++ )
(void) printf( "\t\t%s\n",
n
->in_entries
[i
]->e_name
->rdn_av
.av_struct
);
* add_nonlocalalias - add entry e to the list of nonlocal aliases
static add_nonlocalalias( e
, pindex
)
if ( pindex
== NULLINDEX
)
if ( pindex
->i_nonlocalaliases
== (struct entry
**) 0 ) {
pindex
->i_nonlocalaliases
= (struct entry
**) malloc(
sizeof(struct entry
*) * 2 );
pindex
->i_nonlocalaliases
[ 0 ] = (struct entry
*) 0;
/* first, check for duplicates */
for ( i
= 0, tmp
= pindex
->i_nonlocalaliases
;
*tmp
!= (struct entry
*) 0;
pindex
->i_nonlocalaliases
= (struct entry
**) realloc(
(char *)pindex
->i_nonlocalaliases
, (unsigned) sizeof(struct entry
*) * (i
+ 2) );
pindex
->i_nonlocalaliases
[ i
] = e
;
pindex
->i_nonlocalaliases
[ i
+ 1 ] = NULLENTRY
;
* addnonleafkids - add entry e to the list of nonlocal kids kept
static add_nonleafkid( e
, pindex
)
if ( pindex
== NULLINDEX
)
if ( pindex
->i_nonleafkids
== (struct entry
**) 0 ) {
pindex
->i_nonleafkids
= (struct entry
**) malloc( sizeof(Entry
)
pindex
->i_nonleafkids
[ 0 ] = (struct entry
*) 0;
/* first, check for duplicates */
for ( i
= 0, tmp
= pindex
->i_nonleafkids
; *tmp
!= (struct entry
*) 0;
pindex
->i_nonleafkids
= (struct entry
**) realloc(
(char *)pindex
->i_nonleafkids
, (unsigned)sizeof(struct entry
*) * (i
+ 2) );
pindex
->i_nonleafkids
[ i
] = e
;
pindex
->i_nonleafkids
[ i
+ 1 ] = NULLENTRY
;
* delete_nonleafkid - delete a reference to nonleaf child entry e
static delete_nonleafkid( e
, pindex
)
if ( pindex
->i_nonleafkids
== (struct entry
**) 0 ) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("Index has no non-leaf entries"));
for ( i
= 0, tmp
= pindex
->i_nonleafkids
; *tmp
; tmp
++, i
++ )
if ( *tmp
== (struct entry
*) 0 ) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("Cannot find non-leaf entry"));
for ( j
= i
+ 1; pindex
->i_nonleafkids
[ j
]; j
++ )
pindex
->i_nonleafkids
[ j
- 1 ] = pindex
->i_nonleafkids
[ j
];
* delete_nonlocalalias - delete a reference to nonlocal alias entry e
static delete_nonlocalalias( e
, pindex
)
if ( pindex
->i_nonlocalaliases
== (struct entry
**) 0 ) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("index has no non-local aliases"));
for ( i
= 0, tmp
= pindex
->i_nonlocalaliases
; *tmp
; tmp
++, i
++ )
if ( *tmp
== (struct entry
*) 0 ) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("Cannot find non-local alias"));
for ( j
= i
+ 1; pindex
->i_nonlocalaliases
[ j
]; j
++ )
pindex
->i_nonlocalaliases
[ j
- 1 ] =
pindex
->i_nonlocalaliases
[ j
];
* turbo_attr_insert -- mark entry e as having attribute value val in
* index for attribute type attr.
static turbo_attr_insert( pindex
, e
, attr
, values
)
/* find the appropriate index */
for ( i
= 0; i
< turbo_index_num
; i
++ )
if ( AttrT_cmp( pindex
[ i
].i_attr
, attr
) == 0 )
if ( i
== turbo_index_num
) {
LLOG( log_dsap
, LLOG_EXCEPTIONS
, ("turbo_attr_insert: cannot find optimized attribute") );
for ( av
= values
; av
!= NULLAV
; av
= av
->avseq_next
) {
imem
= (Index_node
*) malloc( sizeof(Index_node
) );
imem
->in_value
= (caddr_t
) AttrV_cpy( &av
->avseq_av
);
imem
->in_entries
= (struct entry
**) malloc( sizeof(struct
imem
->in_entries
[ 0 ] = (struct entry
*) e
;
* Now we insert the entry into the appropriate index.
* If the attribute has a soundex approximate matching
* function, we insert the entry into the appropriate
* soundex index for that attribute.
/* a return of OK means it was the first one inserted */
if ( avl_insert( &pindex
[ i
].i_root
, (caddr_t
) imem
, index_cmp
,
AttrV_free( (AttributeValue
) imem
->in_value
);
free( (char *) imem
->in_entries
);
if ( approxfn( attr
->oa_syntax
) != soundex_match
)
for ( word
= (char *) av
->avseq_av
.av_struct
; word
;
word
= next_word( word
) ) {
imem
= (Index_node
*) malloc( sizeof(Index_node
) );
imem
->in_value
= (caddr_t
) code
;
imem
->in_entries
= (struct entry
**) malloc(
sizeof(struct entry
*) );
imem
->in_entries
[ 0 ] = (struct entry
*) e
;
if ( avl_insert( &pindex
[i
].i_sroot
, (caddr_t
) imem
, sindex_cmp
,
free( (char *) imem
->in_value
);
free( (char *) imem
->in_entries
);
* turbo_add2index -- search through the given entry's attribute list for
* attrs to optimize. if an attr to optimize is found, we add that attribute
* along with a pointer to the corresponding entry to the appropriate
Entry e
; /* the entry these attrs belong to */
Attr_Sequence as
, entry_find_type();
extern AttributeType at_masterdsa
, at_slavedsa
;
if ( sibling_index
== (Avlnode
*) 0 && subtree_index
== (Avlnode
*) 0 )
nonleaf
= (entry_find_type( e
, at_masterdsa
) != NULLATTR
||
entry_find_type( e
, at_slavedsa
) != NULLATTR
);
pdn
= get_copy_dn( parent
);
sibindex
= get_sibling_index( pdn
);
/* for each attribute in the entry... */
for ( as
= e
->e_attributes
; as
!= NULLATTR
; as
= as
->attr_link
) {
opt
= turbo_isoptimized( as
->attr_type
);
(void) turbo_attr_insert( sibindex
, e
, as
->attr_type
,
if ( e
->e_alias
&& (! siblings( dn
, sibindex
->i_dn
)) )
add_nonlocalalias( e
, sibindex
);
/* could be a subtree index with all parents & this node */
for ( tmp
= e
; tmp
->e_parent
; tmp
= tmp
->e_parent
) {
tmpdn
= get_copy_dn( tmp
);
if ( subindex
= get_subtree_index( tmpdn
) ) {
(void) turbo_attr_insert( subindex
, e
,
as
->attr_type
, as
->attr_value
);
pcmp
= prefix( subindex
->i_dn
,
if ( pcmp
!= 0 && pcmp
!= -1 ) {
add_nonleafkid(e
, subindex
);
* turbo_attr_delete -- delete entry e from index for values of attribute
static turbo_attr_delete( pindex
, e
, attr
, values
)
/* find the appropriate index */
for ( i
= 0; i
< turbo_index_num
; i
++ )
if ( AttrT_cmp( pindex
[ i
].i_attr
, attr
) == 0 )
if ( i
== turbo_index_num
) {
LLOG( log_dsap
, LLOG_EXCEPTIONS
, ("turbo_attr_delete: cannot find optimized attribute") );
for ( av
= values
; av
!= NULLAV
; av
= av
->avseq_next
) {
node
= (Index_node
*) avl_find( pindex
[ i
].i_root
,
(caddr_t
) &av
->avseq_av
, (IFP
)indexav_cmp
);
if ( node
== NULLINDEXNODE
) {
LLOG( log_dsap
, LLOG_EXCEPTIONS
, ("Optimized attribute value not found!\n") );
/* find the entry we want to delete */
for ( j
= 0; j
< node
->in_num
; j
++, p
++ )
if ( *p
== (struct entry
*) e
)
if ( j
== node
->in_num
) {
LLOG( log_dsap
, LLOG_EXCEPTIONS
, ("Optimized av entry not found") );
if ( --(node
->in_num
) == 0 ) {
imem
= (Index_node
*) avl_delete( &pindex
[ i
].i_root
,
(caddr_t
) &av
->avseq_av
, indexav_cmp
);
( void ) AttrV_free( (AttributeValue
) imem
->in_value
);
( void ) free( (char *) imem
->in_entries
);
( void ) free( (char *) imem
);
for ( k
= j
; k
< node
->in_num
; k
++ )
node
->in_entries
[ k
+ 1 ];
node
->in_entries
= (struct entry
**)
realloc( (char *) node
->in_entries
, (unsigned) node
->in_num
* sizeof(struct entry
*) );
/* if there's a soundex index, delete from that too */
if ( pindex
[i
].i_sroot
== NULLAVL
)
for ( word
= av
->avseq_av
.av_struct
; word
!= NULL
;
word
= next_word( word
) ) {
* not finding the node is ok if the entry happens
* to be the only one with this code and was deleted
* on a previous pass through this loop. we hope.
if ((imem
= (Index_node
*) avl_find(pindex
[i
].i_sroot
,
code
, index_soundex_cmp
)) == NULLINDEXNODE
) {
for ( j
= 0; j
< imem
->in_num
; j
++, p
++ )
if ( *p
== (struct entry
*) e
)
* not finding the entry is this is ok for the soundex
* index since an entry can appear more than once and
* might have already been deleted on a previous pass
if ( --(imem
->in_num
) == 0 ) {
avl_delete( &pindex
[ i
].i_sroot
,
(caddr_t
) code
, index_soundex_cmp
);
free( (char *) imem
->in_value
);
free( (char *) imem
->in_entries
);
for ( k
= j
; k
< imem
->in_num
; k
++ )
imem
->in_entries
= (struct entry
**)
realloc( (char *) imem
->in_entries
,
(unsigned) imem
->in_num
* sizeof(struct entry
*) );
* turbo_index_delete -- delete attribute index entries for the given
* entry from the attribute index associated with the entry's parent
if ( subtree_index
== NULLAVL
&& sibling_index
== NULLAVL
)
pdn
= get_copy_dn( parent
);
sibindex
= get_sibling_index( pdn
);
/* for each attribute in the entry... */
for ( as
= e
->e_attributes
; as
!= NULLATTR
; as
= as
->attr_link
) {
if ( turbo_isoptimized( as
->attr_type
) == 0 )
(void) turbo_attr_delete( sibindex
, e
, as
->attr_type
,
for ( tmp
= e
; tmp
; tmp
= tmp
->e_parent
) {
tmpdn
= get_copy_dn( tmp
);
if ( subindex
= get_subtree_index( tmpdn
) ) {
(void) turbo_attr_delete( subindex
, e
,
as
->attr_type
, as
->attr_value
);
/* now delete references in nonleafkids and nonlocalaliases... */
if ( sibindex
&& e
->e_alias
&& (! siblings( dn
, sibindex
->i_dn
)) )
delete_nonlocalalias( e
, sibindex
);
if ( nonleaf
== 0 && e
->e_alias
== NULLDN
)
for ( tmp
= e
; tmp
; tmp
= tmp
->e_parent
) {
tmpdn
= get_copy_dn( tmp
);
if ( subindex
= get_subtree_index( tmpdn
) ) {
pcmp
= prefix( subindex
->i_dn
, e
->e_alias
);
if ( pcmp
!= 0 && pcmp
!= -1 )
delete_nonlocalalias( e
, subindex
);
delete_nonleafkid( e
, subindex
);
* turbo_isoptimized -- return TRUE if attr is to be optimized, FALSE
turbo_isoptimized( attr
)
for ( i
= 0; i
< turbo_index_num
; i
++ ) {
if ( AttrT_cmp( attr
, turbo_index_types
[ i
] ) == 0 )
* turbo_optimize -- add attribute attr to the list of attributes to be
* optimized this routine creates an empty index and arranges for the
* attribute to be optimized during loading.
if ( (a
= str2AttrT( attr
)) == NULLAttrT
) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("Bad attribute type (%s)", attr
));
if ( subtree_index
|| sibling_index
)
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("WARNING: optimized attributes MUST be specified before subtree or sibling index"));
if ( turbo_index_types
== (AttributeType
*) 0 )
turbo_index_types
= (AttributeType
*) malloc(
sizeof(AttributeType
*));
turbo_index_types
= (AttributeType
*) realloc(
(char *) turbo_index_types
, (unsigned) (turbo_index_num
+ 1) *
sizeof(AttributeType
*));
if ( turbo_index_types
== (AttributeType
*) 0 )
fatal(66, "turbo_optimize: malloc failed!\n");
turbo_index_types
[ turbo_index_num
] = AttrT_cpy(a
);
* index_subtree - arrange for the subtree starting at tree to be indexed.
if ( (dn
= str2dn( tree
)) == NULLDN
) {
LLOG( log_dsap
, LLOG_EXCEPTIONS
, ("Invalid subtree (%s)\n", tree
) );
pindex
= new_index( dn
);
if ( avl_insert( &subtree_index
, (caddr_t
) pindex
, i_cmp
, i_dup
) == NOTOK
) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("Subtree index for %s already exists\n", tree
));
* index_siblings - arrange for the children of parent to be indexed.
if ( (dn
= str2dn( parent
)) == NULLDN
) {
LLOG( log_dsap
, LLOG_EXCEPTIONS
, ("Invalid parent (%s)\n", parent
) );
pindex
= new_index( dn
);
if ( avl_insert( &sibling_index
, (caddr_t
) pindex
, i_cmp
, i_dup
) == NOTOK
) {
LLOG(log_dsap
, LLOG_EXCEPTIONS
, ("Sibling index for %s already exists\n", parent
));