%:- module(persistent_term_index,
%	  [ persistent_term_index/2,
%	    persistent_term_index_open/0
%	  ]
%	 ).

:- ensure_loaded(common).
cvs_id('$Id: persistent_term_index.pl,v 1.10 2004/10/21 18:50:04 sandro Exp $').
/*

   Offers a PERSISTENT numbering for terms.

   Thread-safe but not at all multi-process safe because pai_counter
   is in memory.

*/


%%  persistent_term_index(?Term, ?Index)
%%
%%      +Term, -Index     returns the Index for known
%%                        terms; assigns and stores
%%                        one for new terms.
%%      +Term, +Index     check
%%      -Term, +Index     fast reverse index
%%      -Term, -Index     database traversal
%%
persistent_term_index(Term, Index) :-
	ground(Term),
	\+ground(Index),
	flag(pai_t2n, T2N, T2N),
	(   once(db_get('$db'(T2N), Term, Index))
	->  true
	;   with_mutex(pai_mutex,
		       unsafe_persistent_term_index_add(Term,
							Index)
		      )
	).
persistent_term_index(Term, Index) :-
	ground(Term),
	ground(Index),
	flag(pai_t2n, T2N, T2N),
	once(db_get('$db'(T2N), Term, Index)).
persistent_term_index(Term, Index) :-
	\+ground(Term),
	ground(Index),
	flag(pai_n2t, N2T, N2T),
	once(db_get('$db'(N2T), Index, Term)).
persistent_term_index(Term, Index) :-
	\+ground(Term),
	\+ground(Index),
	flag(pai_n2t, N2T, N2T),
	db_enum('$db'(N2T), Index, Term).

unsafe_persistent_term_index_add(Term, Index) :-
	flag(pai_t2n, T2N, T2N),
	flag(pai_n2t, N2T, N2T),
	flag(pai_counter, Index, Index+1),
	db_put('$db'(T2N), '.', Index),   % leave this out sometimes?
	db_put('$db'(T2N), Term, Index),
	db_put('$db'(N2T), Index, Term).

persistent_term_index_open :-
	db_open(term_index__2, update, '$db'(T2N),
		[duplicates(false), key(term), value(c_long)]),
	db_open(index_term__2, update, '$db'(N2T),
		[duplicates(false), key(c_long), value(term)]),
	flag(pai_t2n, _, T2N),
	flag(pai_n2t, _, N2T),
	(   db_get('$db'(T2N), '.', HighestUsed)
	->  Next is HighestUsed+1
	;   Next is 1
	),
	flag(pai_counter, _, Next).

persistent_term_index_clear :-
	throw(this_is_not_safe_with_db_open).
%	persistence_delete_file(index_term/2),
%	persistence_delete_file(term_index/2).

	/*
./configure --enable-mt --prefix /usr/local/pl-2004-08-27
make
make install
PATH=(use above, and provide SWIPL and PL)	  
cd packages
./configure
make
make install

mkdir -p /usr/lib/swi-prolog/lib/i386
/usr/bin/install -c -m 755 db4pl.so /usr/local/pl-2004-08-27/lib/swi-prolog/lib/i386
/usr/bin/install -c -m 644 db.pl /usr/local/pl-2004-08-27/lib/swi-prolog/library

	  **USE: **
/usr/bin/install -c -m 755 db4pl.so /usr/local/pl-2004-08-27/lib/pl-5.3.20/lib/i686-linux
/usr/bin/install -c -m 644 db.pl /usr/local/pl-2004-08-27/lib/pl-5.3.20/library

	ERROR: (/usr/local/pl-2004-08-27/lib/pl-5.3.20/library/db.pl:46):
        db4pl: cannot open shared object file: No such file or directory
Warning: (/usr/local/pl-2004-08-27/lib/pl-5.3.20/library/db.pl:46):
        Goal (directive) failed: db: (initialization load_foreign_library(foreign(db4pl)))

 /usr/local/pl-2004-08-27/bin/pl

	  
*/


% the first time, this will assign foo & bar; there-after it will
% check they are the same.   This assumes that no prior-qtests will
% do any persistent_term_index stuff....
%
/*
   This wont actually work on the running system, were have lots
   of other persistent terms, and this may not have been the first.
  
user:qtest :-
	persistent_term_index(foo, X),
	X = 1,
	persistent_term_index(bar(baz), Y),
	Y = 2,
	persistent_term_index(A, 1),
	A = foo,
	persistent_term_index(B, 2),
	B = bar(baz).
*/

	

	
	
