/* File:      flrstoragebase.P - access to base facts
**
** Author(s): Michael Kifer
**
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 1999-2001
**
** FLORA-2 is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
** 
** FLORA-2 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.  See the GNU Library General Public License for
** more details.
** 
** You should have received a copy of the GNU Library General Public License
** along with FLORA-2; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
** 
** 
*/

%% This file exists in order to isolate Flora's access to base facts
%% and make it possible to easily switch the access methods

:- compiler_options([xpp_on]).

#include "flora_terms.flh"
#include "flora_porting.flh"

:- export
	flora_db_insert_base/2,
	flora_db_delete_base/2,
	flora_db_insert_base_bt/2,
	flora_db_delete_base_bt/2,
	flora_db_find_base/2,
	flora_db_commit/1,
	flora_db_reclaim_space/1.


#define FLORA_USE_TRIES

#ifdef FLORA_USE_TRIES

:- import
	storage_find_fact/2,
	storage_insert_fact/3,
	storage_delete_fact/3,
	storage_insert_fact_bt/3,
	storage_delete_fact_bt/3,
	storage_commit/1,
	storage_reclaim_space/1
   from storage.

flora_db_insert_base(StorageName,Call) :-
	storage_insert_fact(StorageName,Call,_ResultFlag).

flora_db_delete_base(StorageName,Call) :-
	storage_delete_fact(StorageName,Call,_ResultFlag).

flora_db_insert_base_bt(StorageName,Call) :-
	storage_insert_fact_bt(StorageName,Call,_ResultFlag).

flora_db_delete_base_bt(StorageName,Call) :-
	storage_delete_fact_bt(StorageName,Call,_ResultFlag).

flora_db_find_base(StorageName,Call) :-
	storage_find_fact(StorageName,Call).

flora_db_commit(StorageName) :-
	storage_commit(StorageName).

flora_db_reclaim_space(StorageName) :-
	storage_reclaim_space(StorageName).

#else

%% Here we need to implement backtrackable updates using assert and retract_nr

#include "storage_xsb_defs.h"
#include "builtin.h"


storage_builtin(_BuiltinNumber,_StorageName,_Handle,_Snapshot,_Changed) :-
	'_$builtin'(STORAGE_BUILTIN).


%% Inserts facts. On backtracking, the fact is deleted.
storage_insert_fact_bt(StorageName,Fact,Inserted) :-	
	triehandle_for_storage(StorageName,H,Snapshot),
	trie_intern(Fact, H, Leaf, New, _),
	(New == 0
	->  Inserted=1,  % new fact inserted
	    mark_storage_changed_bt(StorageName),
	    (  true
	    ; %% On backtracking
		triehandle_for_storage(StorageName,_,NewSnapshot),
		(NewSnapshot =< Snapshot
		-> trie_unintern_nr(H, Leaf), fail 
		)
	    )
	; Inserted=0	 % fact was already there: no action
	).


%% Nonbacktrackable insert
storage_insert_fact(StorageName,Fact,Inserted) :-	
	triehandle_for_storage(StorageName,H,_),
	trie_intern(Fact, H, _Leaf, New, _),
	(New == 0
	->  Inserted=1   % new fact inserted
	; Inserted=0	 % fact was already there: no action
	).


%% Backtrackable delete.
%% Doesn't remove anything, but instead "marks" for deletion.
%% On backtracking: unmarks facts that are marked for deletion

storage_delete_fact_bt(StorageName,Fact,Deleted) :-
	triehandle_for_storage(StorageName,H,Snapshot),
	(trie_interned(Fact, H, Leaf, _)
	->  Deleted=1,   % existing fact deleted
	    mark_storage_changed_bt(StorageName),
	    ( trie_unintern_nr(H, Leaf)
	    ; %% On backtracking
		triehandle_for_storage(StorageName,_,NewSnapshot),
		(NewSnapshot =< Snapshot
		-> unmark_uninterned_nr(H, Leaf), fail
		)
	    )
	;   Deleted=0    % non-existing fact: no action
	).

%% Nonbacktrackable delete
storage_delete_fact(StorageName,Fact,Deleted) :-
	triehandle_for_storage(StorageName,H,_),
	(trie_interned(Fact, H, Leaf, _)
	->  Deleted=1,   % existing fact deleted
	    trie_unintern_nr(H, Leaf)
	;   Deleted=0    % non-existing fact: no action
	).

%% deletes the whole trie
storage_delete_all(StorageName) :- 
	triehandle_for_storage(StorageName,H,_),
	storage_builtin(DESTROY_STORAGE_HANDLE,StorageName,_,_,_),
	delete_trie(H).


%% Find fact in storage
storage_find_fact(StorageName,Fact) :-
	triehandle_for_storage(StorageName,H,_),
	trie_interned(Fact, H, _, _).



%% Commit changes to the storage trie associated with StorageName
%% (only if storage has been changed)
storage_commit(StorageName) :-
	( storage_builtin(INCREMENT_STORAGE_SNAPSHOT,StorageName,_,_,_),
	    !
	%% don't backtrack over it
	; fail
	).

%% Reclaims space by removing nodes from the backtrackable insert/keypair trie
%% which were marked for deletion. This should be done only at the top 
%% level of a query.
storage_reclaim_space(StorageName) :-
	triehandle_for_storage(StorageName,H,_),
	trie_reclaim_uninterned_nr(H).


%% Create a new trie or use an existing one 
%% that is already saved as a property of StorageName
triehandle_for_storage(StorageName,Handle,Snapshot) :-
	storage_builtin(GET_STORAGE_HANDLE,StorageName,Handle,Snapshot,_).


%% This one seems no longer used. Check!!!
mark_storage_changed_bt(StorageName) :-
	storage_builtin(MARK_STORAGE_CHANGED,StorageName,_,_,_).


#endif


syntax highlighted by Code2HTML, v. 0.9.1