/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/


#include	<fcntl.h>
#include	"xlerror.h"
#include	"memory_debug.h"
#include	"task.h"
#include	"acrp.h"
#include	"avt.h"
#include	"mp.h"
#include	"gb.h"
#include	"lock_level.h"
#include	"pri_level.h"

typedef struct timeout_list {
	unsigned int		last_purge_time;
	unsigned int		purge_interval;
	unsigned int		last_access;
	unsigned int		create_time;
	L_CHAR *		url;
} TIMEOUT_LIST;

void modify_tick();

MPI_HEADER	mpi_h;
int mpi_list_length;
SEM mpi_lock;
AVT_NODE * purge_timeout_list;

void (*trigger_around_func)
	(int ses,L_CHAR * my_path,AROUND_LIST * al,int flags);

int loop_lock_over_count;
unsigned int loop_lock_timer,loop_lock_dec_time;
int loop_lock_state;
#define LLS_IDLE	0
#define LLS_STABLE	1
#define LLS_OVER	2
#define LLS_STORM	3
#define LLS_DOWN	4

XL_SEXP * get_op();

void gc_gb_sexp();
void dirty_task();
void _new_dirty_task(MAP_PATH_INFO*);
void new_dirty_task(MAP_PATH_INFO*);
XL_SEXP * gb_MPgetLoopLockTable(XLISP_ENV * env,XL_SEXP * s);


void
init_fetch()
{

	mpi_h.next = (MAP_PATH_INFO*)&mpi_h;
	mpi_h.prev = (MAP_PATH_INFO*)&mpi_h;
	mpi_lock = new_lock(LL_ACRP);
	loop_lock_state = LLS_STABLE;
	new_tick(modify_tick,MODIFY_CHECK_INTERVAL,0);
/*
	create_task(dirty_task,0,PRI_FETCH);
*/
	set_env(gblisp_top_env1,l_string(std_cm,"MPgetLoopLockTable"),
		get_func_prim(gb_MPgetLoopLockTable,FO_APPLICATIVE,0,1,1));

}


int
_check_loop_max(int max)
{
MP_WORK w;
int save;
int ret;
	get_mp_work(&w,0);
	save = 0;
/*
ss_printf("max (%i) %i %i %i %i\n",
loop_lock_state,
max,
w.loop_lock_max,
get_xltime()-loop_lock_timer,
loop_lock_over_count);
*/

	if ( w.loop_lock_max < LOOP_LOCK_TOLERANCE )
		w.loop_lock_max = LOOP_LOCK_TOLERANCE;

	save = 0;
	ret = 0;

	switch ( loop_lock_state ) {
	case LLS_IDLE:
		if ( max <= w.loop_lock_max ) {
			if ( loop_lock_timer + LOOP_LOCK_TIMEOUT
					< get_xltime() ) {
				w.loop_lock_max /= 2;
				if ( max > w.loop_lock_max ) {
					w.loop_lock_max = 8*max;
					loop_lock_state = LLS_STABLE;
				}
				if ( 8*max > w.loop_lock_max ) {
					loop_lock_state = LLS_STABLE;
				}
				loop_lock_timer = get_xltime();
				save = 1;
			}
			if ( 8*max > w.loop_lock_max ) {
				loop_lock_state = LLS_STABLE;
			}
			break;
		}
		loop_lock_over_count = 1;
		w.loop_lock_max = max;
		loop_lock_timer = get_xltime();
		loop_lock_state = LLS_OVER;
		save = 1;
		break;
	case LLS_STABLE:
		if ( max <= w.loop_lock_max )
			break;
		w.loop_lock_max = max;
		loop_lock_over_count = 1;
		loop_lock_state = LLS_OVER;
		loop_lock_timer = get_xltime();
		save = 1;
		break;
	case LLS_OVER:
		if ( loop_lock_timer + 2*LOOP_LOCK_TIMEOUT
				< get_xltime() ) {
			loop_lock_over_count = 0;
			loop_lock_state = LLS_IDLE;
			loop_lock_timer = get_xltime();
			w.loop_lock_max = 32*w.loop_lock_max;
			save = 1;
			break;
		}
		if ( max <= w.loop_lock_max )
			break;
		w.loop_lock_max = max;
		save = 1;
		loop_lock_over_count ++;
		if ( loop_lock_over_count > LOOP_LOCK_COUNT ) {
			loop_lock_state = LLS_STORM;
			loop_lock_timer = get_xltime();
			break;
		}
		break;
	case LLS_STORM:
		if ( loop_lock_timer + 2*LOOP_LOCK_TIMEOUT
				< get_xltime() ) {
			loop_lock_state = LLS_DOWN;
			loop_lock_timer = get_xltime();
			break;
		}
		if ( max >= w.loop_lock_max )
			ret = -1;
		break;
	case LLS_DOWN:
		if ( loop_lock_timer + LOOP_LOCK_TIMEOUT
				< get_xltime() ) {
			loop_lock_state = LLS_IDLE;
			loop_lock_timer = get_xltime();
		}
		if ( max <= w.loop_lock_max )
			break;
		w.loop_lock_max = 8*max;
		save = 1;
		loop_lock_state = LLS_IDLE;
		loop_lock_timer = get_xltime();
		break;
	default:
		er_panic("check_loop_max");
	}
/* end: */
	if ( save )
		set_mp_work(&w);
	return ret;
}


int
check_loop_max(int max)
{
int ret;
	lock_task(mpi_lock);
	ret = _check_loop_max(max);
	unlock_task(mpi_lock,"check_loop_max");
	return ret;
}

void
insert_mpi_ring(MAP_PATH_INFO * m1,MAP_PATH_INFO * m2)
{
	m2->h.prev = m1;
	m2->h.next = m1->h.next;
	m2->h.prev->h.next = m2;
	m2->h.next->h.prev = m2;
}

void
delete_mpi_ring(MAP_PATH_INFO * m)
{
	m->h.prev->h.next = m->h.next;
	m->h.next->h.prev = m->h.prev;
}


L_CHAR *
get_access_path(URL * u,char * prefix)
{
L_CHAR * filename;
L_CHAR * _filename;
        _filename=get_xlsys_path(u);
	filename=get_append_path(_filename,prefix);
	d_f_ree(_filename);
	return filename;
}

void
load_all(XL_SEXP * s)
{
	for ( ; get_type(s) == XLT_PAIR ; s = cdr(s) );
}

int
_purge_timeout_cmp(TIMEOUT_LIST * tl1,TIMEOUT_LIST * tl2)
{
	return l_strcmp(tl1->url,tl2->url);
}


TIMEOUT_LIST *
_search_purge_timeout(L_CHAR * url)
{
AVT_NODE * a, * a1;
TIMEOUT_LIST * tl;
	tl = d_alloc(sizeof(*tl));
	tl->last_purge_time = 0;
	tl->purge_interval = MPI_REMOTE_LIFE_TIME_START;
	tl->url = ll_copy_str(url);
	tl->create_time = get_xltime();
	a = d_alloc(sizeof(*a));
	a->data = tl;
	a1 = avt_insert(&purge_timeout_list,a,_purge_timeout_cmp);
	if ( a1 != a ) {
		d_f_ree(tl->url);
		d_f_ree(tl);
		d_f_ree(a);

		tl = a1->data;

/*
ss_printf("PURGE HIT %ls %i\n",
tl->url,
tl->purge_interval);
*/

	}

/*
else
ss_printf("PURGE NEW %ls\n",tl->url);
*/

	tl->last_access = get_xltime();
	return tl;
}

unsigned int
_get_purge_timeout(L_CHAR * url)
{
TIMEOUT_LIST * tl;
unsigned int tt;
	tl = _search_purge_timeout(url);
	if ( tl->last_purge_time == 0 ) {
		tt = get_xltime() - tl->create_time;
		if ( tt > MPI_REMOTE_LIFE_TIME_MAX )
			tt = MPI_REMOTE_LIFE_TIME_MAX;
		if ( tt > tl->purge_interval )
			tl->purge_interval = tt;
	}
//ss_printf("_get_purge %i %i %i\n",tl->last_purge_time,tt,tl->purge_interval);
	return 2*tl->purge_interval;
}

void
_set_purge_timeout(L_CHAR* url)
{
TIMEOUT_LIST * tl;
unsigned int tt;
	tt = get_xltime();
	tl = _search_purge_timeout(url);
	if ( tl->last_purge_time ) {
		tl->purge_interval =
			0.9*tl->purge_interval +
			0.1*(tt - tl->last_purge_time);
		if ( tl->last_purge_time < MPI_REMOTE_LIFE_TIME_MIN )
			tl->last_purge_time = MPI_REMOTE_LIFE_TIME_MIN;
		if ( tl->last_purge_time > MPI_REMOTE_LIFE_TIME_MAX )
			tl->last_purge_time = MPI_REMOTE_LIFE_TIME_MAX;

/*
ss_printf("SP HIT %ls %i %i\n",
url,tl->purge_interval,
tt - tl->last_purge_time);
*/

	}

/*
else
ss_printf("SP NEW %ls %i %i\n",
url,tl->purge_interval,
tt);
*/

	tl->last_purge_time = tt;
}



unsigned int
get_purge_timeout(L_CHAR * url)
{
unsigned int ret;
	lock_task(mpi_lock);
	ret = _get_purge_timeout(url);
	unlock_task(mpi_lock,"get_purge_timeout");
	return ret;
}

void
set_purge_timeout(L_CHAR * url)
{
	lock_task(mpi_lock);
	_set_purge_timeout(url);
	unlock_task(mpi_lock,"get_purge_timeout");
}

XL_SEXP * 
remote_fetch(int ses,URL * u)
{
XL_SEXP * ret;
XL_SEXP * gt;
L_CHAR * f;

//ss_printf("REMOTE FETCH %ls\n",get_url_str2(u));

	gc_push(0,0,"remote_fetch");
	gt = get_symbol(l_string(std_cm,"Get"));

	set_attribute(gt,
		l_string(std_cm,"mode"),
		l_string(std_cm,"mpt"));

	ret = remote_session(
		gblisp_top_env0,
		ses,
		u,
		l_string(std_cm,"gbstd"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(List(gt,
			get_string(f = get_url_filepath(u)),
			-1),
			-1),
		0,0,0,0);
	d_f_ree(f);

	load_all(ret);
	if ( get_type(ret) != XLT_PAIR )
		ret = 0;
	gc_pop(ret,gc_gb_sexp);
	return ret;
}


XL_SEXP *
local_fetch(unsigned int * mod,URL * u,char * prefix)
{
L_CHAR * filename;
XL_SEXP * ret;
U_STAT buf;
STREAM * st;

CALL_LOCK_DESCRIPTER lr;

	if ( mod )
		*mod = 0;
	filename = get_url_filepath(u);
	if ( filename == 0 )
		return 0;
	d_f_ree(filename);
	filename = get_access_path(u,prefix);

	lr = call_lock(filename,CLT_READ_LOCK,0,0);

	st = s_open_file(n_string(std_cm,filename),O_RDONLY);
	if ( st == 0 ) {
		ret = 0;
		goto end;
	}

	ret = init_parse(st,filename,filename);

	switch ( get_type(ret) ) {
	case XLT_ERROR:
	case XLT_NULL:

		ret = 0;
		goto end;
	case XLT_PAIR:
		break;
	default:
		ret = 0;
		goto end;
	}
	u_stat(n_string(std_cm,filename),&buf);
	if ( mod )
		*mod = buf.us_mtime;
	load_all(ret);
	ret = get_el(ret,1);
end:
	call_unlock(lr);
	d_f_ree(filename);
	return ret;
}


int
check_exist(L_CHAR * path)
{
L_CHAR * filename;
int ret;
STREAM * st;
URL u;

	get_url2(&u,path);
	filename = get_access_path(&u,".mta");
	free_url(&u);
	if ( filename == 0 )
		return -1;
	st = s_open_file(n_string(std_cm,filename),O_RDONLY);
	if ( st == 0 ) {
		ret = -1;
		goto end;
	}
	s_close(st);
	ret = 0;
end:
	d_f_ree(filename);
	return ret;
}

void
free_around_list(AROUND_LIST * a)
{
AROUND_LIST * aa;
	for ( ; a ; ) {
		aa = a->next;
		if ( a->map )
			d_f_ree(a->map);
		if ( a->crd )
			d_f_ree(a->crd);
		if ( a->me )
			d_f_ree(a->me);
		if ( a->mpt )
			free_mpt(a->mpt);
		d_f_ree(a);
		a = aa;
	}
}


void
free_mpi(MAP_PATH_INFO * m)
{
	free_url(&m->u);
	free_mpt(m->mpt);
	free_around_list(m->alist);
	if ( m->my_pri )
		d_f_ree(m->my_pri);
	d_f_ree(m);
}

XL_SEXP *
fi_of_entry_dir(ACRP_DIR * d)
{
	return List(
		n_get_symbol("dir"),
		get_integer(d->hops,0),
		get_string(d->map),
		get_string(d->crd),
		-1);
}

XL_SEXP *
fi_of_entry(int id,ACRP_ENTRY * e)
{
XL_SEXP * ret;
int i;
	ret = 0;
	for ( i = ACRP_DIR_NOS-1 ; i >= 0 ; i -- ) {
		if ( e->dir[i].hops < 0 )
			continue;
		ret = cons(fi_of_entry_dir(&e->dir[i]),ret);
	}
	return cons(n_get_symbol("entry"),
		cons(get_integer(id,0),
		cons(get_string(e->pri),
		cons(get_integer(e->sum,0),ret))));

}

XL_SEXP *
fi_of_one_mpt(MAP_PATH_TABLE * m)
{
XL_SEXP * ret;
int i;
	ret = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		if ( m->ent[i].dir[0].hops < 0 )
			continue;
		ret = cons(fi_of_entry(i,&m->ent[i]),ret);
	}
	return cons(n_get_symbol("level"),
		cons(get_integer(m->level,0),ret));
}

XL_SEXP *
fileimage_of_mpt(MAP_PATH_TABLE * t)
{
XL_SEXP * ret;
MAP_PATH_TABLE * m;
	ret = 0;
	for ( m = t ; m ; m = m->next ) {
		ret = cons(fi_of_one_mpt(m),ret);
	}
	return cons(n_get_symbol("mpt"),ret);
}

XL_SEXP *
fileimage_of_mpi(MAP_PATH_INFO * mpi)
{
XL_SEXP * ret;
MAP_PATH_TABLE * m;
	ret = 0;
	for ( m = mpi->mpt ; m ; m = m->next ) {
		ret = cons(fi_of_one_mpt(m),ret);
	}
	return cons(n_get_symbol("mpt"),
		cons(
			_get_cid_sexp(mpi),
		cons(
			List(n_get_symbol("regulation"),
				get_integer(mpi->regulation,0),
				-1),
			ret)));
}

int
get_mp_port()
{
int p;
XL_SEXP * port;
static int acrp_port;
	if ( acrp_port )
		return acrp_port;
	gc_push(0,0,"acrp_port");
	port = eval(gblisp_top_env1,get_symbol(l_string(std_cm,"MPPort")));
	switch ( get_type(port) ) {
	case XLT_ERROR:
		if ( (port->err.code & XLE_VERB_MASK) == XLE_EXIT ) {
			gc_pop(0,0);
			return 0;
		}
		print_sexp(s_stderr,port,0);
		s_printf(s_stderr,"\n");
		er_panic("get_mp_port");
	case XLT_INTEGER:
		p = port->integer.data;
		break;
	default:
		s_printf(s_stderr,"type missmatch");
		print_sexp(s_stderr,port,0);
		s_printf(s_stderr,"\n");
		er_panic("get_mp_point(2)");
	}
	gc_pop(0,0);
	acrp_port = p;
	return p;
}



void
set_my_pri(MAP_PATH_INFO * m,L_CHAR * filename)
{
int port;
int t;
char * buf;
int len;
URL u;
L_CHAR * fp;
char * my_name;

	if ( m->my_pri )
		d_f_ree(m->my_pri);
	get_url2(&u,filename);
	fp = get_url_filepath(&u);
	free_url(&u);
	t = get_xltime();
	port = get_my_port();

	my_name = d_alloc(100);
	strcpy(my_name,n_string(std_cm,get_xllisp_site()));

	len = l_strlen(fp) + 100 + strlen(my_name);
	buf = d_alloc(sizeof(L_CHAR)*len);
	sprintf(buf,"%012o:%s:%i:%s",
		t,my_name,port,n_string(std_cm,fp));
	d_f_ree(my_name);
	m->my_pri = nl_copy_str(std_cm,buf);
	d_f_ree(buf);
	d_f_ree(fp);
}

int
set_my_pri_force(MAP_PATH_INFO * m,L_CHAR * ref)
{
L_CHAR * my_name;
unsigned int d;
int len;
int p;
char * buf;
	for ( my_name = m->my_pri;
		*my_name != ':';
		my_name ++);
	d = 0;
	for ( p = 0 ; ref[p] && ref[p] != ':' ; p ++ ) {
		d = d*8;
		d += ref[p]-'0';
	}
	if ( d == 0 )
		er_panic("set_my_pri_force");
	len = 30 + l_strlen(my_name);
	buf = d_alloc(sizeof(L_CHAR)*len);
	sprintf(buf,"%012o%s",d-1,n_string(std_cm,my_name));
	if ( m->my_pri )
		d_f_ree(m->my_pri);
	m->my_pri = nl_copy_str(std_cm,buf);
	d_f_ree(buf);
	return 0;
}

L_CHAR * 
get_my_pri_from_mpt(MAP_PATH_TABLE * t)
{
	if ( t == 0 )
		return 0;
	for ( ; t->next ; t = t->next );
	return ll_copy_str(t->ent[t->id].pri);
}


int
check_my_pri(L_CHAR * pri,L_CHAR * filename)
{
L_CHAR * p1;
L_CHAR * buf2;
char * buf1;
int port;
int ret;
char * my_name;

	if ( pri == 0 )
		return -1;
	for ( p1 = pri ; *p1 && *p1 != ':' ; p1 ++ );
	if ( *p1 == 0 )
		return -1;
	p1 ++;

	my_name = d_alloc(100);
	strcpy(my_name,n_string(std_cm,get_xllisp_site()));

	buf1 = d_alloc(l_strlen(filename)*sizeof(L_CHAR) + 
		strlen(my_name) + 20);
	port = get_my_port();
	sprintf(buf1,"%s:%i:%s",my_name,port,n_string(std_cm,filename));
	d_f_ree(my_name);
	buf2 = nl_copy_str(std_cm,buf1);
	if ( l_strcmp(buf2,p1) == 0 )
		ret = 0;
	else	ret = -1;
	d_f_ree(buf1);
	d_f_ree(buf2);
	return ret;
}

int
check_mpt_duplicate2(char * str,ACRP_ENTRY * e)
{
int i;
ACRP_DIR * d1;
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ ) {
		d1 = &e->dir[i];
		if ( d1->hops < 0 )
			break;
		if ( d1->map == 0 ) {
			fprintf(stderr,"%s ",str);
			er_panic("map");
		}
		if ( d1->crd == 0 ) {
			fprintf(stderr,"%s ",str);
			er_panic("crd");
		}
	}
	return 0;
}

int
check_mpt2(char * str,MAP_PATH_TABLE * m)
{
int i;
ACRP_ENTRY * e;
	for ( ; m ; m = m->next ) {
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			e = &m->ent[i];
			check_mpt_duplicate2(str,e);
		}
	}
	return 0;
}

int
check_mpt_duplicate(ACRP_ENTRY * e)
{
int i,j;
ACRP_DIR * d1,* d2;
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ ) {
		d1 = &e->dir[i];
		if ( d1->hops < 0 )
			break;
		for ( j = i+1 ; j < ACRP_DIR_NOS ; j ++ ) {
			d2 = &e->dir[j];
			if ( d2->hops < 0 )
				break;
			if ( d1->map == 0 && d2->map == 0 )
				return -1;
			if ( d1->map == 0 )
				continue;
			if ( d2->map == 0 )
				continue;
			if ( l_strcmp(d1->map,d2->map) == 0 )
				return -1;
		}
	}
	return 0;
}

int
check_mpt(MAP_PATH_TABLE * m,L_CHAR * filename,int type)
{
int level;
int i;
ACRP_ENTRY * e;
int f;
MAP_PATH_TABLE * last;
URL u;
L_CHAR * fp;
int ret;
	if ( filename ) {
		get_url2(&u,filename);
		fp = get_url_filepath(&u);
		free_url(&u);
	}
	else {
		fp = 0;
	}
	ret = -1;
	if ( m == 0 )
		goto illeagal;
	level = 0;
	last = 0;
	for ( ; m ; last = m, m = m->next , level ++ ) {
		ret = -2;
		if ( m->level != level )
			goto illeagal;
		f = 0;
		for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
			e = &m->ent[i];
			if ( e->dir[0].hops < 0 )
				continue;
			if ( e->pri == 0 ||
				l_strcmp(e->pri,l_string(std_cm,"")) == 0 ) {
				ret = -3;
				goto illeagal;
			}
			if ( e->dir[0].hops == 0 ) {
				ret = -4;
				if ( f == 1 )
					goto illeagal;
				f = 1;
				ret = -5;
				if ( i != m->id )
					goto illeagal;
			}
			ret = -7;
			if ( check_mpt_duplicate(e) < 0 )
				goto illeagal;
		}
		ret = -8;
		if ( f == 0 )
			goto illeagal;
	}
	ret = -9;
	if ( fp )
		d_f_ree(fp);
	return 0;
illeagal:
	if ( fp )
		d_f_ree(fp);
	return ret;
}

void
test_err(char * str)
{
URL u;
	get_url2(&u,l_string(std_cm,"/tokyo/meiji/Cood-Japan.crd"));
	free_url(&u);
	if ( mpi_h.next == (MAP_PATH_INFO*)&mpi_h )
		return;
	if ( ((int)mpi_h.next->u.db) < 0x80 ) {
		fprintf(stderr,"%s",str);
		er_panic("test_err");
	}
}


AROUND_LIST *
copy_around_list(AROUND_LIST * a)
{
AROUND_LIST * ret, ** ap, * a1;
	ret = 0;
	ap = &ret;
	for ( ; a ; a = a->next ) {
		a1 = d_alloc(sizeof(*a1));
		a1->next = 0;
		if ( a->crd )
			a1->crd = ll_copy_str(a->crd);
		else	a1->crd = 0;
		if ( a->map )
			a1->map = ll_copy_str(a->map);
		else	a1->map = 0;
		if ( a->me )
			a1->me = ll_copy_str(a->me);
		else	a1->me = 0;
		a1->mpt = 0;
		*ap = a1;
		ap = &a1->next;
	}
	return ret;
}

void
_set_mpi_around_list(MAP_PATH_INFO * mpi,
	AROUND_LIST * a,
	int copy_flag)
{
	free_around_list(mpi->alist);
	if ( copy_flag ) {
		mpi->alist = copy_around_list(a);
	}
	else {
		mpi->alist = a;
	}
	mpi->alist_fetch = 1;
	if ( mpi->access_time )
		mpi->access_time = get_xltime();
	if ( mpi->first_access_time == 0 )
		mpi->first_access_time = get_xltime();
}

void
set_mpi_around_list(MAP_PATH_INFO * mpi,
	AROUND_LIST * a,
	int copy_flag)
{
	lock_task(mpi_lock);
	_set_mpi_around_list(mpi,a,copy_flag);
	unlock_task(mpi_lock,"set_mpi_around_list");
}


AROUND_LIST *
make_around_list_part(XL_SEXP * par,XL_SEXP * chi)
{
L_CHAR * src,*dest, * map;
AROUND_LIST * a,* aa;
XL_SEXP * r;

	a = 0;
	for ( ; get_type(chi) == XLT_PAIR ; chi = cdr(chi) ) {
		r = car(chi);
		if ( get_type(r) != XLT_PAIR )
			continue;
		get_sd_url(&src,&dest,&map,r);

		if ( map == 0 || src == 0 || dest == 0 )
			continue;
		aa = d_alloc(sizeof(*aa));
		aa->map = ll_copy_str(map);
		aa->crd = ll_copy_str(src);
		aa->me = ll_copy_str(dest);
		aa->mpt = 0;
		aa->next = a;
		a = aa;
	}
	for ( ; get_type(par) == XLT_PAIR ; par = cdr(par) ) {
		r = car(par);
		if ( get_type(r) != XLT_PAIR )
			continue;
		get_sd_url(&src,&dest,&map,r);
		if ( map == 0 || src == 0 || dest == 0 )
			continue;
		aa = d_alloc(sizeof(*aa));
		aa->map = ll_copy_str(map);
		aa->crd = ll_copy_str(dest);
		aa->me = ll_copy_str(src);
		aa->mpt = 0;
		aa->next = a;
		a = aa;
	}
	return a;
}



AROUND_LIST *
get_mpi_around(MAP_PATH_INFO * mpi,int mpi_around_flag)
{
AROUND_LIST * a1;
XL_SEXP * chi,*par;
L_CHAR * filename;
	lock_task(mpi_lock);
	if ( mpi->alist_fetch == 0 || mpi_around_flag ) {
		unlock_task(mpi_lock,"get_mpi_around_all");

		filename = ll_copy_str(get_url_str2(&mpi->u));
		gc_push(0,0,"make_around_list");
		chi = filtering_crd(get_crd_chi(filename));
		par = filtering_crd(get_crd_par(filename));
		a1 = make_around_list_part(par,chi);
		gc_pop(0,0);
		d_f_ree(filename);

		lock_task(mpi_lock);
		_set_mpi_around_list(mpi,a1,0);
	}
	a1 = copy_around_list(mpi->alist);
	unlock_task(mpi_lock,"get_mpi_around_all");
	return a1;
}

int
localhost_check(URL * up,L_CHAR * url_str,char * msg)
{
int local_ip;
int p;
L_CHAR nul[2] = {(L_CHAR)'*',0};
	gc_push(0,0,"get_mpi1");
	local_ip = get_xllisp_site_ip().d.v4;
	p = get_my_port();
	if ( url_str == 0 )
		url_str = nul;
	if ( cmp_site(up->server,0,up->port,
			0,local_ip,p) ) {
		log_printf(LOG_WARNING,LOG_LAYER_GB,0,
			"(%s)get_mpi ses=0 REMOTE_CK %ls(%ls)\n",
			msg,get_url_str2(up),url_str);
		gc_pop(0,0);
		return -1;
	}
	gc_pop(0,0);
	return 0;
}

int
localhost_check_str(L_CHAR * url_str,char *msg)
{
URL u;
int ret;
	get_url2(&u,url_str);
	ret = localhost_check(&u,url_str,msg);
	free_url(&u);
	return ret;
}


MAP_PATH_INFO *
get_mpi(int ses,L_CHAR * url_str,int type)
{
MAP_PATH_INFO * m, * m1;
URL u;
XL_SEXP * ret;
int p;
int sts;
static int local_ip;
unsigned int mod;
int site;

	if ( local_ip == 0 )
		local_ip = get_xllisp_site_ip().d.v4;

	switch ( type&MPI_TYPE ) {
	case MPI_READ:
	case MPI_WRITE:
		break;
	default:
		er_panic("get_mpi");
	}
	p = get_my_port();
	get_url2(&u,url_str);
	lock_task(mpi_lock);
	if ( u.proto == 0 )
		u.proto = nl_copy_str(std_cm,"xlp");
	if ( u.server == 0 )
		u.server = ll_copy_str(get_xllisp_site());
	if ( u.port == 0 )
		u.port = p;
	if ( u.db[0] != '/' ) {
	L_CHAR * buf;
	int len;
		len = l_strlen(u.db);
		buf = d_alloc(sizeof(L_CHAR)*(len+2));
		l_strcpy(&buf[1],u.db);
		buf[0] = '/';
		d_f_ree(u.db);
		u.db = buf;
	}
	if ( l_strcmp(u.server,get_xllisp_site()) == 0 &&
			u.port == p ) {
		site = MPIS_LOCAL;
	}
	else if ( cmp_site(u.server,0,u.port,
			0,local_ip,p) == 0 ) {
		site = MPIS_LOCAL;
	}
	else	site = MPIS_REMOTE;
	for ( m = mpi_h.next ; m != (MAP_PATH_INFO*)&mpi_h; m = m->h.next ) {
		switch ( m->sts ) {
		case MPIS_ERROR:
		case MPIS_FETCH:
			if ( url_cmp(&u,&m->u) == 0 )
				goto fit;
			continue;
		case MPIS_LOCAL:
			if ( site != MPIS_LOCAL )
				continue;
			if ( l_strcmp(u.db,m->u.db) )
				continue;
			if ( l_strcmp(u.resource,m->u.resource) )
				continue;
			goto fit;
		case MPIS_REMOTE:
			if ( site != MPIS_REMOTE )
				continue;
			if ( url_cmp(&u,&m->u) == 0 )
				goto fit;
			continue;
		default:
			er_panic("get_mpi");
		}
	}
	goto no_fit;

fit:
	m->waiting ++;
	if ( m->sts != MPIS_FETCH && (type & MPI_NOCACHE) ) {
		for ( ; m->lock ; ) {
			sleep_task((int)m,mpi_lock);
			lock_task(mpi_lock);
		}
		delete_mpi_ring(m);
		mpi_list_length --;
		goto no_fit;
	}
	for ( ; m->sts == MPIS_FETCH ; ) {
		sleep_task((int)m,mpi_lock);
		lock_task(mpi_lock);
	}
	for ( ; m->lock < 0 || 
		((type&MPI_TYPE) == MPI_WRITE && m->lock) ; ) {
		if ( type & MPI_NOWAIT ) {
			m->waiting --;
			unlock_task(mpi_lock,"get_mpi");
			return MPI_NOWAIT_RETURN;
		}
		sleep_task((int)m,mpi_lock);
		lock_task(mpi_lock);
	}
	delete_mpi_ring(m);
	insert_mpi_ring((MAP_PATH_INFO*)&mpi_h,m);
	m->waiting --;
	if ( (type&MPI_TYPE) == MPI_READ )
		m->lock ++;
	else	m->lock = -1;
	if ( m->access_time )
		m->access_time = get_xltime();
	if ( m->first_access_time == 0 )
		m->first_access_time = get_xltime();
	unlock_task(mpi_lock,"get_mpi");
	free_url(&u);
	return m;

no_fit:
	gc_push(0,0,"get_mpi1");
	local_ip = get_xllisp_site_ip().d.v4;
	if ( cmp_site(u.server,0,u.port,
			0,local_ip,p) && ses == 0 ) {
	  	unlock_task(mpi_lock,"get_mpi1");
		log_printf(LOG_WARNING,LOG_LAYER_GB,0,
			"get_mpi ses=0 REMOTE %ls(%ls)\n",
			get_url_str2(&u),url_str);
		free_url(&u);
		gc_pop(0,0);
		return 0;
	}
	gc_pop(0,0);


	m = d_alloc(sizeof(*m));
	memset(m,0,sizeof(*m));
	m->dirty_mode = 0;
	m->waiting = 1;
	m->alist_fetch = 0;
	m->alist = 0;
	m->u = u;
	m->sts = MPIS_FETCH;
	m->lock = 0;
	m->mpt = 0;
	m->regulation = 0;
	m->my_pri = 0;
	m->modify = 0;
	m->cid_flag = 0;
	m->access_time = get_xltime();
	m->first_access_time = 0;

	insert_mpi_ring((MAP_PATH_INFO*)&mpi_h,m);
	mpi_list_length ++;
	for ( ; mpi_list_length > MPI_LL_MAX ; ) {
		for ( m1 = mpi_h.prev ;
			m1 != (MAP_PATH_INFO*)&mpi_h;
			m1 = m1->h.prev )
			if ( m1->lock == 0 && m1->sts != MPIS_FETCH &&
					m1->waiting == 0 &&
					m1->dirty_mode == DM_IDLE )
				break;
		if ( m1 == (MAP_PATH_INFO*)&mpi_h )
			break;
		delete_mpi_ring(m);
		free_mpi(m);
		mpi_list_length --;
	}
	unlock_task(mpi_lock,"get_mpi");

	gc_push(0,0,"get_mpi");
	local_ip = get_xllisp_site_ip().d.v4;
	if ( cmp_site(u.server,0,u.port,
			0,local_ip,p) == 0 ) {
		ret = local_fetch(&mod,&u,".mpt");
		m->modify = mod;
		sts = MPIS_LOCAL;
	}
	else if ( ses ) {
	 	ret = remote_fetch(ses,&u);
		sts = MPIS_REMOTE;
	}
	else {
		er_panic("get_mpi");
	}


	lock_task(mpi_lock);
	m->waiting --;
	if ( (type&MPI_TYPE) == MPI_READ )
		m->lock ++;
	else	m->lock = -1;
	if ( ret == 0 ) {
		m->sts = MPIS_ERROR;
	}
	else {
	unsigned int reg;
	int r;
	int cid_flag;
		m->sts = sts;
/*
log_print_sexp(LOG_DEBUG,LOG_LAYER_GB,0,"get_mpt",ret,0);
log_printf(LOG_DEBUG,LOG_LAYER_GB,0,"\n");
*/
		m->mpt = get_mpt(&reg,&cid_flag,ret);
		if ( (r=check_mpt(m->mpt,url_str,sts)) < 0 ) {
/*
printf("REMOTE %s %i - %x %i\n",
n_string(std_cm,u.server),u.port,local_ip,(int)p);
ss_printf("check %i %s %x\n",(int)r,n_string(std_cm,url_str),(int)m->mpt);
print_sexp(s_stdout,ret,0);
ss_printf("CHECK END\n");
*/
			free_mpt(m->mpt);
			m->mpt = 0;
			m->sts = MPIS_ERROR;
		}
		else if ( sts == MPIS_REMOTE )
			m->regulation = 0;
		else 	m->regulation = reg;
		m->cid_flag = cid_flag;
	}
	gc_pop(0,0);
	m->my_pri = get_my_pri_from_mpt(m->mpt);
	if ( m->my_pri == 0 )
		set_my_pri(m,url_str);
	delete_mpi_ring(m);
	insert_mpi_ring((MAP_PATH_INFO*)&mpi_h,m);
	wakeup_task((int)&m);
	if ( m->access_time )
		m->access_time = get_xltime();
	if ( m->first_access_time == 0 )
		m->first_access_time = get_xltime();
	unlock_task(mpi_lock,"fetch");
	return m;
}

int dirty_task_nos;

void
_new_dirty_task(MAP_PATH_INFO * m)
{
	switch ( m->dirty_mode ) {
	case DM_IDLE:
		m->dirty_mode = DM_DIRTY;
		break;
	case DM_DIRTY:
		break;
	case DM_WRITE:
		m->dirty_mode = DM_WRITE_DIRTY;
		break;
	case DM_WRITE_DIRTY:
		break;
	}
	if ( dirty_task_nos == 0 )
		create_task(dirty_task,0,PRI_FETCH);
	wakeup_task((int)dirty_task);
}

void
new_dirty_task(MAP_PATH_INFO * m)
{
	lock_task(mpi_lock);
	_new_dirty_task(m);
	unlock_task(mpi_lock,"dirty_task");
}

void
dirty_task()
{
XL_SEXP * image;
XL_INTERPRETER * xli;
MAP_PATH_INFO * m;
XL_SEXP * gt;
L_CHAR * filename;
CALL_LOCK_DESCRIPTER cld;
STREAM * st;
U_STAT buf;
AROUND_LIST * al;
int ses;
int lock_cnt;

	lock_task(mpi_lock);
	dirty_task_nos ++;
	unlock_task(mpi_lock,"dirty_task");

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);

retry:
	lock_task(mpi_lock);
retry2:
	if ( dirty_task_nos > 1 ) {
		dirty_task_nos --;
		unlock_task(mpi_lock,"dirty_task");
		goto end_task;
	}
	lock_cnt = 0;
	for ( m = mpi_h.next ; m != (MAP_PATH_INFO*)&mpi_h; 
			m = m->h.next ) {
		if ( m->sts != MPIS_LOCAL )
			continue;
		if ( m->dirty_mode != DM_DIRTY )
			continue;
		if ( m->lock < 0 ) {
//ss_printf("DT lock\n");
			lock_cnt ++;
			continue;
		}
		m->lock ++;
//ss_printf("DT 1\n");

		m->dirty_mode = DM_WRITE;

		gc_push(0,0,"dirty_task");

		image = fileimage_of_mpi(m);

		unlock_task(mpi_lock,"dirty_task");

		gt = n_get_symbol("?xl");
		set_attribute(gt,
				l_string(std_cm,"version"),
				l_string(std_cm,"1.0"));
		set_attribute(gt,
				l_string(std_cm,"eoncoding"),
				l_string(std_cm,"EUC-JP"));

		filename = get_access_path(&m->u,".mpt");
//ss_printf("DT 2 %ls\n",filename);
		
		cld = call_lock(filename,CLT_WRITE_LOCK,0,0);

		st = s_open_file(
			n_string(std_cm,filename),
			O_CREAT|O_TRUNC|O_RDWR,
			0644);
		if ( st == 0 )
			goto end;
		print_sexp(
			st,
			List(	List(gt,-1),
				image,
				-1),
			PF_MULTI_ROOT|PF_INDENT);
		s_printf(st,"\n");
		s_close(st);

		u_stat(n_string(std_cm,filename),&buf);
		m->modify = buf.us_mtime;
	end:
		call_unlock(cld);

		d_f_ree(filename);

		if ( trigger_around_func ) {
		L_CHAR * my_path;
			lock_task(mpi_lock);
			dirty_task_nos --;
			unlock_task(mpi_lock,"dirty_task");

			my_path = ll_copy_str(get_url_str2(&m->u));
			al = get_mpi_around(m,0);
			(*trigger_around_func)(ses,my_path,al,TAF_REMOTE);
			free_around_list(al);
			d_f_ree(my_path);

			lock_task(mpi_lock);
			dirty_task_nos ++;
			unlock_task(mpi_lock,"dirty_task");

		}


		gc_pop(0,0);
//ss_printf("DT 3\n");


 

		lock_task(mpi_lock);

		m->lock --;
		wakeup_task((int)m);

		switch ( m->dirty_mode ) {
		case DM_IDLE:
			er_panic("???");
			break;
		case DM_DIRTY:
			er_panic("???");
			break;
		case DM_WRITE:
			m->dirty_mode = DM_IDLE;
			break;
		case DM_WRITE_DIRTY:
			m->dirty_mode = DM_DIRTY;
			break;
		default:
			er_panic("dirty_mode");		}
		goto retry2;
	}
//ss_printf("SLEEP DT\n");
	if ( dirty_task_nos > 1 ) {
		dirty_task_nos --;
		unlock_task(mpi_lock,"dirty_task");
		goto end_task;
	}
	if ( lock_cnt ) {
		unlock_task(mpi_lock,"dirty_task");
		sleep_sec(5);
		goto retry;
	}
	sleep_task((int)dirty_task,mpi_lock);
//ss_printf("WAKEUP DT\n");
	goto retry;


end_task:
	close_session(ses);
	close_self_interpreter();
}



void
flush_mpi(MAP_PATH_INFO * m)
{

int r;
	if ( m == 0 )
		return;
	lock_task(mpi_lock);
	if ( m->lock > 0 )
		m->lock --;
	else if ( m->sts == MPIS_ERROR ) {
		m->lock = 0;
	}
	else {


r = check_mpt(m->mpt,0,0);
if ( r < 0 ) {
printf("flush check %i\n",r);
print_mpt(m->mpt);
er_panic("flush");
}

		if ( m->lock == -2 && m->sts == MPIS_LOCAL ) {

			_new_dirty_task(m);


		}
		m->lock = 0;
	}

	wakeup_task((int)m);
	unlock_task(mpi_lock,"flush_mpi");

}


void
xx_dirty_mpi(MAP_PATH_INFO * m,char * __f,int __l)
{

//ss_printf("dirty %s:%i\n",__f,__l);

	lock_task(mpi_lock);
	if ( m->lock >= 0 )
		goto end;
	m->lock = -2;
	m->regulation = get_xltime();
end:
	unlock_task(mpi_lock,"dirty_mpi");
}

MAP_PATH_TABLE *
xx_get_mpi_cp_mpt(int ses,L_CHAR * url_str,int type,
char * __file,int __line)
{
MAP_PATH_INFO * mpi;
MAP_PATH_TABLE * m,** mp;
MAP_PATH_TABLE * m1, * m2;


	mpi = get_mpi(ses,url_str,MPI_READ|(type&(MPI_NOCACHE|MPI_NOWAIT)));
	if ( mpi == 0 )
		return 0;
	if ( mpi == MPI_NOWAIT_RETURN )
		return MPT_NOWAIT_RETURN;
	m = 0;
	mp = &m;
	for ( m1 = mpi->mpt ; m1 ; m1 = m1->next ) {
		m2 = xx_copy_mpt(m1,__file,__line);
		m2->next = 0;
		*mp = m2;
		mp = &m2->next;
	}
	flush_mpi(mpi);
	return m;
}


void
modify_tick()
{
MAP_PATH_INFO * m, * m1;
L_CHAR * filename;
U_STAT buf;

	lock_task(mpi_lock);
	for ( m = mpi_h.prev ; m != (MAP_PATH_INFO*)&mpi_h ; ) {
		if ( m->lock )
			goto next;
		if ( m->waiting )
			goto next;
		if ( m->sts == MPIS_FETCH )
			goto next;
		if ( m->dirty_mode != DM_IDLE )
			goto next;
		if ( m->sts == MPIS_REMOTE ) {
			if ( m->first_access_time &&
				get_xltime() - m->first_access_time
					> _get_purge_timeout(
						get_url_str2(&m->u)) )
{//ss_printf("REMOTE DEL %i\n",get_xltime() - m->first_access_time);
				goto del;
}
			else	goto next;
		}
		if ( m->sts == MPIS_ERROR )
			goto del;
		filename = get_access_path(&m->u,".mpt");
		if ( filename == 0 )
			goto del;
		u_stat(n_string(std_cm,filename),&buf);
		d_f_ree(filename);
		if ( buf.us_mtime == m->modify )
			goto next;
	del:
		m1 = m->h.prev;
		delete_mpi_ring(m);
		free_mpi(m);
		mpi_list_length --;
		m = m1;
		continue;
	next:
		m = m->h.prev;
	}
	unlock_task(mpi_lock,"modify_tick");
}

int *
url2cid(L_CHAR * url)
{
URL u;
int port,ip;
MAP_PATH_TABLE * t, * t1;
int len;
int * ret;
int i;
int ses;

	get_url2(&u,url);
	port = get_my_port();
	ip = get_xllisp_site_ip().d.v4;
	ses = open_session(SEST_OPTIMIZE);
	t = get_mpi_cp_mpt(ses,url,0);
	if ( t == 0 )
		return 0;
	t1 = t;
	for ( len = 0 ; t1 ; t1 = t1->next , len ++ );
	ret = d_alloc(sizeof(int)*(len+1));
	t1 = t;
	for ( i = 1 ; i <= len ; i ++ , t1 = t1->next )
		ret[i] = t1->id;
	ret[0] = len;
	close_session(ses);

	free_mpt(t);

	return ret;
}

int
mpi_purge(L_CHAR * str)
{
URL u;
MAP_PATH_INFO * m;
int f;

	f = -1;
	get_url2(&u,str);
	if ( u.server == 0 && u.port == 0 )
		u.port = get_my_port();
	lock_task(mpi_lock);
	for ( m = mpi_h.next ;
			m != (MAP_PATH_INFO*)&mpi_h;
			m = m->h.next ) {
		if ( url_cmp(&m->u,&u) != 0 )
			continue;
		if ( m->lock ) {
			m->access_time = 0;
			break;
		}
		if ( m->waiting ) {
			m->access_time = 0;
			break;
		}
		if ( m->sts == MPIS_FETCH ) {
			m->access_time = 0;
				break;
		}
		_set_purge_timeout(str);
		delete_mpi_ring(m);
		free_mpi(m);
		mpi_list_length --;
		f = 0;
		break;
	}
	unlock_task(mpi_lock,"mpi_purge");

	free_url(&u);

	return f;
}



INVALID_PRI_TABLE * invalid_pri_tbl;

INVALID_PRI_TABLE * 
new_invalid_pri_table()
{
INVALID_PRI_TABLE * ret;
	ret = d_alloc(sizeof(*ret));
	memset(ret,0,sizeof(*ret));
	return ret;
}

void
copy_invalid_data_set(INVALID_DATA_SET * d1,INVALID_DATA_SET * d2)
{
	if ( d1->start_point )
		d_f_ree(d1->start_point);
	*d1 = *d2;
	d1->start_point = ll_copy_str(d2->start_point);
}


INVALID_PRI *
_search_ipt(int * target,L_CHAR * pri,INVALID_DATA_SET * ds,int new_flag)
{
int len;
INVALID_PRI_TABLE * tbl, * tbl_2;
int i;
INVALID_PRI_ENTRY * e;
INVALID_PRI * ret;
	len = target[0];
	if ( len <= 0 )
		return 0;

	if ( invalid_pri_tbl == 0 ) {
		tbl = new_invalid_pri_table();
		tbl->level = 0;
		invalid_pri_tbl = tbl;
	}

	for ( ; invalid_pri_tbl->level + 1 < len ; ) {
		tbl = new_invalid_pri_table();
		tbl->level = invalid_pri_tbl->level + 1;
		tbl->ent[0].tbl = invalid_pri_tbl;
		invalid_pri_tbl = tbl;
	}
	tbl = invalid_pri_tbl;

	for ( ; tbl->level + 1 > len ; ) {
		if ( tbl->ent[0].tbl == 0 ) {
			if ( new_flag == 0 )
				return 0;
			tbl_2 = new_invalid_pri_table();
			tbl_2->level = tbl->level-1;
			tbl->ent[0].tbl = tbl_2;
		}
		tbl = tbl->ent[0].tbl;
	}
	e = 0;
	for ( i = 1 ; i <= len ; i ++ ) {
		if ( target[i] == SUBID_DONTCARE )
			break;
		if ( target[i] < 0 ||
				target[i] >= ACRP_SUBID_NOS )
			break;
		if ( tbl == 0 )
			return 0;
		e = &tbl->ent[target[i]];
		if ( e->tbl == 0 ) {
			if ( new_flag && tbl->level ) {
				e->tbl = new_invalid_pri_table();
				e->tbl->level = tbl->level - 1;
			}
		}
		tbl = e->tbl;
	}

	if ( e == 0 )
		return 0;
	if ( pri == 0 )
		return e->pri;
	for ( ret = e->pri ; ret ; ret = ret->next )
		if ( l_strcmp(ret->pri,pri) == 0 ) {

			if ( ds ) {
				copy_invalid_data_set(&ret->d,ds);
			}
ss_printf("S IPT-1 HIT(%i) %s\n",new_flag,
s_print_cid(target));
			if ( new_flag <= 1 && ret->access_time )
				ret->access_time = get_xltime();


			return ret;
		}

	if ( new_flag == 0 )
		return 0;
	ret = d_alloc(sizeof(*ret));
	memset(ret,0,sizeof(*ret));
	ret->pri = ll_copy_str(pri);
	copy_invalid_data_set(&ret->d,ds);
	ret->next = e->pri;
	ret->access_time = get_xltime();
	e->pri = ret;

ss_printf("S IPT-NEW HIT(%i) %s\n",new_flag,
s_print_cid(target));

	return ret;
}


void
_clean_invalid_pri(INVALID_PRI ** p,
		unsigned int n_time,
		int * target,
		void (*func)(INVALID_PRI*,int *))
{
INVALID_PRI * q;
	for ( ; *p ; ) {
		q = *p;

//ss_printf("CLEAN %ls\n",q->pri);

		if ( n_time - q->access_time < INVALID_PRI_TIMEOUT ) {

			if ( func )
				(*func)(q,target);

			p = &q->next;
		}
		else {

			*p = q->next;
			d_f_ree(q->pri);
			d_f_ree(q);
		}
	}
}


int
_clean_invalid_pri_table(INVALID_PRI_TABLE * tbl,
	unsigned int n_time,
	int lev,
	int * target,
	void (*func)(INVALID_PRI*,int *))
{
int i,j;
INVALID_PRI_ENTRY * e;
int cnt;
	if ( tbl == 0 )
		return 0;
	cnt = 0;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		e = &tbl->ent[i];
		target[lev] = i;
		for ( j = lev+1 ; j <= target[0] ; j ++ )
			target[j] = SUBID_DONTCARE;
		_clean_invalid_pri(&e->pri,n_time,target,func);
		if ( e->pri )
			cnt ++;
		if ( _clean_invalid_pri_table(e->tbl,n_time,
				lev+1,target,func) )
			cnt ++;
		else	e->tbl = 0;
	}
	if ( cnt == 0 )
		d_f_ree(tbl);
	return cnt;
}



void
delete_ipt(int * target,L_CHAR * pri)
{
INVALID_PRI * d;
	lock_task(mpi_lock);
//ss_printf("DELETE IPT %s\n",s_print_cid(target));
	d = _search_ipt(target,pri,0,0);
	if ( d )
		d->access_time = 0;
	unlock_task(mpi_lock,"search_ipt");
}


int
search_ipt(int * target,L_CHAR * pri,INVALID_DATA_SET * ds,int new_flag)
{
INVALID_PRI * ip;

	lock_task(mpi_lock);
	ip = _search_ipt(target,pri,ds,new_flag);
	unlock_task(mpi_lock,"search_ipt");
	if ( ip )
		return 1;
	return 0;
}

int
clean_invalid_pri_table(void(*func)(INVALID_PRI*,int *))
{
static unsigned int clean_interval;
unsigned int n_time;
int ret;
int * target;
int len;

	lock_task(mpi_lock);
	n_time = get_xltime();
	ret = 0;
	if ( clean_interval < n_time && invalid_pri_tbl ) {
		len = invalid_pri_tbl->level+1 ;
		target = d_alloc(sizeof(int)*(len+1));
		target[0] = len;
		if ( _clean_invalid_pri_table(invalid_pri_tbl,
				n_time,
				1,
				target,
				func) == 0 )
			invalid_pri_tbl = 0;
		clean_interval = n_time + CLEAN_INVALID_PRI_INTERVAL;
		ret = 1;
		d_f_ree(target);
	}
	unlock_task(mpi_lock,"search_ipt");
	return ret;
}

void
clean_invalid_pri_table2()
{
unsigned int n_time;
int * target;
int len;

	lock_task(mpi_lock);
	n_time = get_xltime();
	len = invalid_pri_tbl->level+1 ;
	target = d_alloc(sizeof(int)*(len+1));
	target[0] = len;
	if ( _clean_invalid_pri_table(invalid_pri_tbl,
				n_time,
				1,
				target,
				0) == 0 )
		invalid_pri_tbl = 0;
	d_f_ree(target);
	unlock_task(mpi_lock,"search_ipt");
}

XL_SEXP *
_get_invalid_pri(INVALID_PRI * p,int * target)
{
XL_SEXP * ret;
	ret = 0;
	for ( ; p ; p = p->next ) {
		gc_push(0,0,"pri");
		ret = cons(
			List(	get_string(p->pri),
				cid2list(target),
				-1),
			ret);
		gc_pop(ret,gc_gb_sexp);
	}
	return ret;
}

XL_SEXP * 
_get_loop_lock_table(INVALID_PRI_TABLE * tbl,int * target);

XL_SEXP * 
_get_loop_lock_table(INVALID_PRI_TABLE * tbl,int * target)
{
int i,j;
int lev;
INVALID_PRI_ENTRY * e;
XL_SEXP *ret;

	if ( tbl == 0 )
		return 0;

	ret = 0;
	lev = target[0] - tbl->level;
	for ( i = 0 ; i < ACRP_SUBID_NOS ; i ++ ) {
		for ( j = lev ; j <= target[0] ; j ++ )
			target[j] = SUBID_DONTCARE;
		target[lev] = i;
		e = &tbl->ent[i];
		gc_push(0,0,"loop");
		ret = append(_get_invalid_pri(e->pri,target),ret);
		gc_pop(ret,gc_gb_sexp);
		gc_push(0,0,"loop");
		ret = append(_get_loop_lock_table(e->tbl,target),ret);
		gc_pop(ret,gc_gb_sexp);
	}
	return ret;
}

XL_SEXP * 
get_loop_lock_table();

XL_SEXP * 
get_loop_lock_table()
{
XL_SEXP * ret;
int * target;
	lock_task(mpi_lock);
	if ( invalid_pri_tbl == 0 ) {
		ret = 0;
	}
	else {
		target = d_alloc(sizeof(int)*(invalid_pri_tbl->level+2));
		target[0] = invalid_pri_tbl->level+1;
		gc_push(0,0,"loop");
		ret = _get_loop_lock_table(invalid_pri_tbl,target);
		gc_pop(ret,gc_gb_sexp);
		d_f_ree(target);
	}
	unlock_task(mpi_lock,"get_loop_lock_table");
	return ret;
}


XL_SEXP *
gb_MPgetLoopLockTable(XLISP_ENV * env,XL_SEXP * s)
{
	return get_loop_lock_table();
}



