/**********************************************************************
 
	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	"mp.h"
#include	"lock_level.h"

void modify_tick();

MPI_HEADER	mpi_h;
int mpi_list_length;
SEM mpi_lock;

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
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);
}


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 * f;
int len,slen;
extern L_CHAR * sys_path;
int plen;
	f = get_url_filepath(u);
	plen = strlen(prefix);
	len = l_strlen(f) + (slen = l_strlen(sys_path));
	filename = d_alloc(sizeof(L_CHAR)*(len+plen+10),10);
	l_strcpy(filename,sys_path);
	l_strcpy(&filename[slen],f);
	l_strcpy(&filename[len],l_string(std_cm,prefix));
	d_f_ree(f);
	return filename;
}

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


	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);
	d_f_ree(f);

	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;
int len;
XL_SEXP * ret, * r;
XL_SEXP * s;
U_STAT buf;
STREAM * st;
XL_SEXP * lr, * gt;

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

	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;
	ret = get_el(ret,1);
end:
	d_f_ree(filename);
	return ret;
}


int
check_exist(L_CHAR * path)
{
L_CHAR * filename;
int len;
int ret;
XL_SEXP * s;
STREAM * st;
XL_SEXP * lr, * gt;
URL u;

	get_url2(&u,path,1221);
	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_my_port()
{
int p;
XL_SEXP * port;
static int my_port;
	if ( my_port )
		return my_port;
	gc_push(0,0,"fetch");
	port = eval(gblisp_top_env1,get_symbol(l_string(std_cm,"ServerPort")));
	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_my_port");
	case XLT_INTEGER:
		p = port->integer.data;
		break;
	default:
		fprintf(stderr,"type missmatch");
		fflush(stderr);
		print_sexp(s_stderr,port,0);
		s_printf(s_stderr,"\n");
		er_panic("get_my_port");
	}
	gc_pop(0,0);
	my_port = p;
	return p;
}


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,1222);
	fp = get_url_filepath(&u);
	free_url(&u);
	t = get_xltime();
	port = get_my_port();

	my_name = d_alloc(100,12);
	get_localhostname(my_name);

	len = l_strlen(fp) + 100 + strlen(my_name);
	buf = d_alloc(sizeof(L_CHAR)*len,10);
	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,10);
	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,1435);
}


int
check_my_pri(L_CHAR * pri,L_CHAR * filename)
{
L_CHAR * p1, * p2;
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,12);
	get_localhostname(my_name);

	buf1 = d_alloc(l_strlen(filename)*sizeof(L_CHAR) + 
		strlen(my_name) + 20,23);
	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,1223);
		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"),1224);
	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),26);
		a1->next = 0;
		if ( a->crd )
			a1->crd = ll_copy_str(a->crd,547);
		else	a1->crd = 0;
		if ( a->map )
			a1->map = ll_copy_str(a->map,37);
		else	a1->map = 0;
		if ( a->me )
			a1->me = ll_copy_str(a->me,6);
		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;
}

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),1);
		aa->map = ll_copy_str(map,1404);
		aa->crd = ll_copy_str(src,1403);
		aa->me = ll_copy_str(dest,1402);
		aa->mpt = 0;
		aa->next = a;
		a = aa;
	}
	for ( ; get_type(par) ; 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),1);
		aa->map = ll_copy_str(map,1401);
		aa->crd = ll_copy_str(dest,1400);
		aa->me = ll_copy_str(src,1399);
		aa->mpt = 0;
		aa->next = a;
		a = aa;
	}
	return a;
}



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

		filename = ll_copy_str(get_url_str(&mpi->u),326);
		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;
}


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;

set_cpu_msg(730010);
	if ( local_ip == 0 )
		local_ip = get_localhostip();

	switch ( type&MPI_TYPE ) {
	case MPI_READ:
	case MPI_WRITE:
		break;
	default:
		er_panic("get_mpi");
	}
set_cpu_msg(730020);
	p = get_my_port();
set_cpu_msg(730021);
	get_url2(&u,url_str,1225);
set_cpu_msg(730022);
	lock_task(mpi_lock);
set_cpu_msg(730023);
	if ( u.proto == 0 )
		u.proto = nl_copy_str(std_cm,"xlp");
set_cpu_msg(730024);
	if ( u.server == 0 )
		u.server = ll_copy_str(gblisp_site,1434);
set_cpu_msg(730025);
	if ( u.port == 0 )
		u.port = p;
set_cpu_msg(730030);
	if ( u.db[0] != '/' ) {
	L_CHAR * buf;
	int len;
		len = l_strlen(u.db);
		buf = d_alloc(sizeof(L_CHAR)*(len+2),23);
		l_strcpy(&buf[1],u.db);
		buf[0] = '/';
		d_f_ree(u.db);
		u.db = buf;
	}
set_cpu_msg(730040);
	if ( l_strcmp(u.server,gblisp_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");
		}
	}
set_cpu_msg(730050);
	goto no_fit;

fit:

set_cpu_msg(730060);
	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;
	}
set_cpu_msg(730070);
	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 ; ) {
		sleep_task((int)m,mpi_lock);
		lock_task(mpi_lock);
	}
set_cpu_msg(730080);
	delete_mpi_ring(m);
	insert_mpi_ring((MAP_PATH_INFO*)&mpi_h,m);
	if ( (type&MPI_TYPE) == MPI_READ )
		m->lock ++;
	else	m->lock = -1;
	unlock_task(mpi_lock,"get_mpi");
	free_url(&u);
set_cpu_msg(730090);
	return m;

no_fit:

set_cpu_msg(730100);
	m = d_alloc(sizeof(*m),1002);
	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;

set_cpu_msg(730110);
	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 )
				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");
set_cpu_msg(730120);

	gc_push(0,0,"get_mpi");
	local_ip = get_localhostip();
	if ( cmp_site(u.server,0,u.port,
			0,local_ip,p) == 0 ) {
set_cpu_msg(730130);
		ret = local_fetch(&mod,&u,".mpt");
		m->modify = mod;
		sts = MPIS_LOCAL;
set_cpu_msg(730140);
	}
	else if ( ses ) {
set_cpu_msg(730150);
	 	ret = remote_fetch(ses,&u);
		sts = MPIS_REMOTE;
set_cpu_msg(730160);
	}
	else {
set_cpu_msg(730170);
		lock_task(mpi_lock);
		delete_mpi_ring(m);
		free_mpi(m);
		mpi_list_length --;
		unlock_task(mpi_lock,"get_mpi");
		gc_pop(0,0);
set_cpu_msg(730180);
		return 0;
	}
set_cpu_msg(730190);


	lock_task(mpi_lock);
	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;
set_cpu_msg(730200);
		m->sts = sts;
		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,p);
printf("check %i %s %x\n",r,n_string(std_cm,url_str),m->mpt);
fflush(stdout);
print_sexp(s_stdout,ret,0);
ss_printf("\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;
	}
set_cpu_msg(730210);
	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);
	unlock_task(mpi_lock,"fetch");
set_cpu_msg(730220);
	return m;
}



void
flush_mpi(MAP_PATH_INFO * m)
{
XL_SEXP * s;
L_CHAR * filename;
STREAM * st;
XL_SEXP * gt;
XL_SEXP * lr;
U_STAT buf;

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 ) {
			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");

			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),
					fileimage_of_mpi(m),
					-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:
			d_f_ree(filename);
		}
		m->lock = 0;
	}
	wakeup_task((int)m);
	unlock_task(mpi_lock,"flush_mpi");
}


void
dirty_mpi(MAP_PATH_INFO * m)
{
	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 *
get_mpi_cp_mpt(int ses,L_CHAR * url_str,int type)
{
MAP_PATH_INFO * mpi;
MAP_PATH_TABLE * m,** mp;
MAP_PATH_TABLE * m1, * m2;


set_cpu_msg(730000);
	mpi = get_mpi(ses,url_str,MPI_READ|(type&MPI_NOCACHE));
set_cpu_msg(731000);
	if ( mpi == 0 )
		return 0;
set_cpu_msg(732000);
	m = 0;
	mp = &m;
set_cpu_msg(733000);
	for ( m1 = mpi->mpt ; m1 ; m1 = m1->next ) {
		m2 = copy_mpt(m1);
		m2->next = 0;
		*mp = m2;
		mp = &m2->next;
	}
set_cpu_msg(734000);
	flush_mpi(mpi);
set_cpu_msg(735000);
	return m;
}


void
modify_tick()
{
MAP_PATH_INFO * m, * m1;
L_CHAR * filename;
int one;
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->sts == MPIS_FETCH )
			goto next;
		if ( m->sts == MPIS_REMOTE )
			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;
XL_SEXP * gt;

	get_url2(&u,url,1219);
	port = get_my_port();
	ip = get_localhostip();
	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),1);
	t1 = t;
	for ( i = 1 ; i <= len ; i ++ , t1 = t1->next )
		ret[i] = t1->id;
	ret[0] = len;
	close_session(ses);

	return ret;
}

void
mpi_purge(L_CHAR * str)
{
URL u;
MAP_PATH_INFO * m;
	get_url2(&u,str,1220);
	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 )
			break;
		if ( m->sts == MPIS_FETCH )
			break;
		delete_mpi_ring(m);
		free_mpi(m);
		mpi_list_length --;
		break;
	}
	unlock_task(mpi_lock,"mpi_purge");
	free_url(&u);
}
