Net2/usr/src/contrib/isode/dsap/common/cache.c

/* cache.c - */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/dsap/common/RCS/cache.c,v 7.3 91/02/22 09:18:44 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/dsap/common/RCS/cache.c,v 7.3 91/02/22 09:18:44 mrose Interim $
 *
 *
 * $Log:	cache.c,v $
 * Revision 7.3  91/02/22  09:18:44  mrose
 * Interim 6.8
 * 
 * Revision 7.2  90/10/17  11:41:25  mrose
 * sync
 * 
 * Revision 7.1  90/07/09  14:34:09  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:16:40  mrose
 * Release 6.0
 * 
 */

/*
 *				  NOTICE
 *
 *    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
 *    this agreement.
 *
 */


#include "quipu/util.h"
#include "quipu/dua.h"
#include "quipu/list.h"
#include "quipu/entry.h"
#ifdef TURBO_AVL
#include "quipu/turbo.h"
#endif

extern LLog * log_dsap;
extern Entry database_root;
extern time_t time();
extern int local_cache_size;
#ifdef TURBO_AVL
extern int entryrdn_cmp();
#endif

struct list_cache *list_top = NULLCACHE;
Entry  current_entry = NULLENTRY;
DN     current_dn = NULLDN;
extern time_t cache_timeout;

Entry local_find_entry_aux ();

struct subordinate * subord_cpy (x)
struct subordinate * x;
{
struct subordinate * sub;
struct subordinate * y;
struct subordinate * top;

	if (x == NULLSUBORD)
		return (x);
	
	top = (struct subordinate *) smalloc (sizeof(struct subordinate));
	top->sub_copy =  x->sub_copy;
	top->sub_rdn = rdn_cpy(x->sub_rdn);
	top->sub_aliasentry = x->sub_aliasentry;
	top->sub_next = NULLSUBORD;
	y = top;

	for (x=x->sub_next; x != NULLSUBORD; x=x->sub_next) {
		sub = (struct subordinate *) smalloc (sizeof(struct subordinate));
		sub->sub_copy =  x->sub_copy;
		sub->sub_rdn = rdn_cpy(x->sub_rdn);
		sub->sub_aliasentry = x->sub_aliasentry;
		sub->sub_next = NULLSUBORD;
		y->sub_next = sub;
		y = sub;
	}

	return (top);	
}

/* ARGSUSED */
cache_list (ptr, prob,dn,sizelimit)
struct subordinate *ptr;
int             prob;
DN 		dn;
int 		sizelimit;
{
	struct list_cache *cache;
	struct subordinate *sub;
	register int i;

	if ((cache = find_list_cache (dn,0)) == NULLCACHE) {
		cache = (struct list_cache *) smalloc (sizeof (struct list_cache));
		cache->list_dn = dn_cpy (dn);
		cache->list_subs = subord_cpy (ptr);
		cache->list_sub_top = cache->list_subs;
		cache->list_next = list_top;
		cache->list_problem = prob;
		list_top = cache;
	} else {
		subords_free (cache->list_sub_top);
		cache->list_subs = subord_cpy (ptr);
			cache->list_sub_top = cache->list_subs;
		cache->list_problem = prob;
	}

	for (i=0, sub=cache->list_subs; 
		sub != NULLSUBORD; 
		i++, sub = sub->sub_next);
	cache->list_count = i;

}

delete_list_cache (adn)
DN adn;
{
DN dntop, trail = NULLDN;
struct list_cache *ptr, *lt = NULLCACHE;

	if (adn == NULLDN)
		return;

	dntop = adn;

	for (; adn->dn_parent != NULLDN; adn=adn->dn_parent)
		trail = adn;

	if (trail == NULLDN)
		dntop = NULLDN;
	else
		trail->dn_parent = NULLDN;

        for (ptr = list_top; ptr != NULLCACHE; ptr = ptr->list_next) {
                if (dn_cmp (ptr->list_dn, dntop) == 0) {
			if (lt == NULLCACHE) 
				list_top = ptr->list_next;
			else 
				lt->list_next = ptr->list_next;
			subords_free(ptr->list_sub_top);
			free ((char *)ptr);
			if (trail != NULLDN)
				trail->dn_parent = adn;
			return;
		}
		lt = ptr;
	}
	if (trail != NULLDN)
		trail->dn_parent = adn;
}

struct list_cache *find_list_cache (dn,sizelimit)
DN dn;
int sizelimit;
{
	struct list_cache *ptr;
	int i;
	for (ptr = list_top; ptr != NULLCACHE; ptr = ptr->list_next)
		if (dn_cmp (ptr->list_dn, dn) == 0)
			if ((ptr->list_problem == LSR_NOLIMITPROBLEM) 
				|| ((ptr->list_count >= sizelimit) && (sizelimit != -1)))
				{
				ptr->list_subs = ptr->list_sub_top;
				if (sizelimit == -1) 	
					return (ptr);
				/* only want sizelimit of them */
				for (i=ptr->list_count - sizelimit; i>0; i--)
					ptr->list_subs = ptr->list_subs->sub_next;
				return (ptr);
				}

	return (NULLCACHE);
}



cache_entry (ptr, complete, vals)
EntryInfo      *ptr;
char            complete;
char            vals;
{
	Entry           make_path ();
	DN              dnptr;
	extern 	AttributeType at_alias;
	Attr_Sequence	as, as_merge_aux();

	/* use e_lock to indicate if values are present */

	if (ptr->ent_dn == NULLDN)
		return;

	dn_free (current_dn);

	current_dn = dn_cpy (ptr->ent_dn);

	for (dnptr = current_dn; dnptr->dn_parent != NULLDN; dnptr = dnptr->dn_parent)
		;

	if ((current_entry = local_find_entry_aux (current_dn, FALSE)) != NULLENTRY) {
			
		current_entry->e_age = time((time_t *)0);
		if ((vals && complete) || 
		   ((current_entry->e_data == E_TYPE_CACHE_FROM_MASTER) 
		     && (time((time_t *)0) - current_entry->e_age > cache_timeout))) {
			
			as_free (current_entry->e_attributes);
			current_entry->e_attributes = as_cpy(ptr->ent_attr);
			current_entry->e_lock = vals;
			current_entry->e_complete = complete;
		} else if (!current_entry->e_complete) {
			current_entry->e_complete = complete;
			current_entry->e_attributes = as_merge_aux (current_entry->e_attributes, as_cpy(ptr->ent_attr));
			if (vals != current_entry->e_lock)
				current_entry->e_lock = FALSE;
		} else { 
			current_entry->e_attributes = as_merge_aux (current_entry->e_attributes, as_cpy(ptr->ent_attr));
		}
	} else {
		current_entry = make_path (current_dn);
/*
		current_entry->e_name = rdn_cpy (dnptr->dn_rdn);
*/
		current_entry->e_complete = complete;
		current_entry->e_data = E_TYPE_CACHE_FROM_MASTER;
		current_entry->e_age = time((time_t *)0);
		current_entry->e_lock = vals;
		current_entry->e_attributes = as_cpy(ptr->ent_attr);
		local_cache_size++;
	}

	/* insert alias pointers */
	for ( as = current_entry->e_attributes; as != NULLATTR; as = as->attr_link) {
		if (as->attr_type == at_alias)
			if (as->attr_value)
				current_entry->e_alias = (DN) as->attr_value->avseq_av.av_struct;
	}
}


delete_cache (adn)
DN              adn;
{
	Entry           ptr;

	delete_list_cache (adn);

	if ((ptr = local_find_entry_aux (adn, FALSE)) != NULLENTRY) {
		if (ptr->e_data == E_TYPE_CACHE_FROM_MASTER) {
			local_cache_size--;
#ifdef TURBO_AVL
			if (ptr->e_children != NULLAVL) {
#else
			if (ptr->e_child != NULLENTRY) {
#endif
				ptr->e_data = E_TYPE_CONSTRUCTOR;
				ptr->e_complete = FALSE;	
				as_free (ptr->e_attributes);
				ptr->e_attributes = NULLATTR;
#ifdef TURBO_AVL
			} else {
                                ( void ) avl_delete( &ptr->e_parent->e_children,
                                    (caddr_t) ptr->e_name, entryrdn_cmp );
#else
			} else if ( ptr->e_parent->e_child == ptr ) {
				ptr->e_parent->e_child = ptr->e_sibling;
				entry_free (ptr);
			} else {
				Entry tmp;
				for (tmp=ptr->e_parent->e_child; tmp != NULLENTRY; tmp=tmp->e_sibling) {
					if (tmp->e_sibling == ptr)
						break;
				}
				tmp->e_sibling = ptr->e_sibling ;
				entry_free (ptr);
#endif
			}
		}
	}
}


Entry local_find_entry (object,deref)
DN                      object;
char deref;
{
Entry the_entry;

	if ((the_entry = local_find_entry_aux (object,deref)) == NULLENTRY)
		return NULLENTRY;

	if ((the_entry->e_data == E_TYPE_CACHE_FROM_MASTER) 
		&& (time((time_t *)0) - the_entry->e_age > cache_timeout)) {
		DLOG (log_dsap,LLOG_NOTICE,("local find entry - timeout"));
		return (NULLENTRY);
	} else
		return (the_entry); 
}

Entry local_find_entry_aux (object,deref)
DN                      object;
char deref;
{
Entry  the_entry;
register RDN    b_rdn;
DN     dn;
#ifdef TURBO_AVL
Avlnode	*kids;
#else
register RDN	a_rdn;
#endif

	DLOG (log_dsap,LLOG_TRACE,("local_find_entry_aux"));

	if (database_root == NULLENTRY) 
		return (NULLENTRY);

	if ((dn = object) == NULLDN)
		return (database_root);

	b_rdn = dn->dn_rdn;
#ifdef TURBO_AVL
	if ((kids = database_root->e_children) == NULLAVL)
#else
	if ((the_entry = database_root->e_child) == NULLENTRY) 
#endif
		return (NULLENTRY);

#ifdef TURBO_AVL
	b_rdn = dn->dn_rdn;
#else
	a_rdn = the_entry->e_name ;
#endif

	for(;;) { /* break or return out */
#ifdef TURBO_AVL
		if ((the_entry = (Entry) avl_find(kids, (caddr_t) b_rdn, 
					 entryrdn_cmp)) == NULLENTRY)
			return(NULLENTRY);
#else
		while (rdn_cmp (a_rdn, b_rdn) != OK) {
			the_entry = the_entry->e_sibling ;
			if ( the_entry == NULLENTRY ) 
				return (NULLENTRY);
			a_rdn = the_entry->e_name ;
		}
#endif

		if ( the_entry->e_alias != NULLDN )
			/* got an alias entry */
			if (deref) {
				Entry new_entry;
				if (dn_cmp (the_entry->e_alias,object) == 0) 
					return (NULLENTRY);
				new_entry = local_find_entry (the_entry->e_alias,deref);
				if (new_entry == NULLENTRY ) 
					return (NULLENTRY);
				the_entry = new_entry;
			} else if ( dn->dn_parent == NULLDN) 
				return (the_entry);
			else 
				return (NULLENTRY);

		if ( dn->dn_parent == NULLDN) 
			return (the_entry); 

		dn = dn->dn_parent;
		b_rdn = dn->dn_rdn;

#ifdef TURBO_AVL
		if (the_entry->e_children == NULLAVL)
#else
		if ( the_entry->e_child == NULLENTRY )
#endif
			return (NULLENTRY);

#ifdef TURBO_AVL
		kids = the_entry->e_children;
#else
		the_entry = the_entry->e_child;
		a_rdn = the_entry->e_name;
#endif
	}
	/* NOTREACHED */
}


DN get_copy_dn (entryptr)
Entry entryptr;
{
register DN dn;
register DN dnptr;
register Entry ptr;

	if ((entryptr == NULLENTRY) || (entryptr->e_parent == NULLENTRY))
		return NULLDN;

	dn = dn_comp_new (rdn_cpy (entryptr->e_name));
	for (ptr = entryptr->e_parent; ptr->e_parent != NULLENTRY; ptr = ptr->e_parent) {
		dnptr = dn_comp_new (rdn_cpy (ptr->e_name));
		dnptr->dn_parent = dn;
		dn = dnptr;
	}

	return (dn);
}


IFP unrav_fn = NULLIFP;
IFP schema_fn = NULLIFP;

unravel_attribute (eptr,error)
Entry eptr;
struct DSError * error;
{
	if (unrav_fn == NULLIFP)
		return (OK);
	else
		return ((*unrav_fn)(eptr,error));
}

check_schema (eptr,as,error)
Entry eptr;
Attr_Sequence as;
struct DSError * error;
{
	if (schema_fn == NULLIFP)
		return (OK);
	else 
		return ((*schema_fn)(eptr,as,error));
}


char * new_version ()
{
long clock;
struct UTCtime ut;
extern time_t time();

	(void) time (&clock);
	tm2ut (gmtime (&clock),&ut);
	return (strdup(utct2str(&ut)));
}