<< Prev | - Up - | Next >> |
The following code shows how to create a new Global Store GS. The imported module GlobalStore
implements the GS abstraction. The procedure NewStore
from the GlobalStore
module initialises a GS and offers the Ls
reference in a file or a URL.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create a new global store
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
functor
import
GlobalStore
Connection
Pickle
System(show:Show)
define
Ls
try
{GlobalStore.new ?Ls}
% pickle LS and offer it to clients
{Pickle.save {Connection.offerUnlimited Ls $} './gsticket'}
catch
gs(failed_globalstore_creation) then
{Show errorNewStore }
[] error(url(_ _) debug:_) then {Show 'cannot create url or file '}
[] error(connection(_ _) debug:_) then {Show 'connection Module error'}
end
end
The following functor creates a new user named user1
connected to the GS. The newLocal
method returns a LocalStore
reference to the GS and a NewObj
procedure for creating new objects in the GS. The call throws a gs(connectionfailed)
exception if it fails to connect to GS. In the current release of the GS module, NewObj
is a sited reference i.e it cannot be exported to others users. Each new user will create its own NewObj
reference. Each user has the ability of creating other users by exporting its LocalStore
reference on distant sites.
functor
import
Connection
System(show:Show)
Pickle
define
LS
try LS={Connection.take {Pickle.load './gsticket' $}}
catch
error(url(_ _) debug:_) then {Show 'url or file not found'}
[] error(connection(_ _) debug:_) then {Show connectionfailed}
end
NewObj LocalStore Movehere
try
{LS newLocal(Module user1 ?NewObj ?LocalStore ?Movehere)}
catch gs(connectionfailed)
then
{Show connectionfailed}
end
try {Pickle.save {Connection.offerUnlimited LocalStore $} './client1ticket'}
catch
error(url(_ _) debug:_) then {Show 'cannot create url or file '}
[] error(connection(_ _) debug:_) then {Show 'connection Module error'}
end
end
We show how to create three counter objects in the global store:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Create an object in the store
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Obj1 Obj2 Obj3 are references in
% the local store
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
declare
class Counter
attr val
meth show(Value) Value=@val end
meth inc(Value) val <- @val+Value end
meth init(Value) val <- Value end
end
Obj1 Obj2 Obj3
in
Obj1={NewObj Counter init(0)}
Obj2={NewObj Counter init(0)}
Obj3={NewObj Counter init(0)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% save Obj1 refrence to use it on other users %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{Pickle.save {Connection.offerUnlimited Obj1} 'obj1.tick'}
A transaction is a one argument procedure initiated in its own thread. The variable Out
is a return value of Trans
.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialise transactions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
proc{Trans Out}
if {IsOdd {Obj1 show($)}}
{Obj1 inc(1)}
{Obj1 inc(~1)}
{Obj2 inc(~1)}
{Obj2 inc(2)}
else
skip
end
Out=state({Obj1 show($)})
end
OutPut % Output of Trans
Transid % Transaction Identifier
Res % Transaction Result
in
{LocalStore trans(Trans ?OutPut ?Res)}
%%%% check transaction
%%%% The result is commit, abort
{Wait Res}
{System.show Res}
We use a transaction to have values of objects GS values. The values are globally coherent if Trans
is committed.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Procedure to show a coherent
% snapshot of the global store
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
proc {CoherentSnapshot}
proc{Trans ?Output}
Val1 Val2 Val3 in
{Obj1 show(Val1)}
{Obj2 show(Val2)}
{Obj3 show(Val3)}
Output=state(Val1 Val2 Val3)
end
Transid
Out
Result
in
{LocalStore trans(Trans ?Out ?Result)}
{Wait Result}
if Result==commit then
{Show 'Obj1:'#Out.1#'Obj2:'#Out.2#'Obj3:'#Out.3}
else
skip
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%% Non cohernent query without transaction one can call %%%%%%
%%%%% read only methed that will not change the object state %%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{Show {Obj1 show($)}}
{Show {Obj2 show($)}}
{Show {Obj3 show($)}}
We introduce concurrency inside a transaction at a user by the call {LocalStore newthread(proc {$} {Obj1 inc(1)} end)}
. The call executes the procedure proc {$} {Obj1 inc(1)} end
in its own thread.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialise transactions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
proc{Trans Out}
{Obj1 inc(1)}
{Obj1 inc(~1)}
{Obj2 inc(~1)}
%%% Update is done in a new thread
{LocalStore newthread(proc {$} {Obj1 inc(1)} end)}
%%%%
{Obj2 inc(2)}
{Obj1 inc(1)}
Out=state({Obj1 show($)})
end
OutPut % Output of Trans
Transid % Transaction Identifier
Res
in
{LocalStore trans(Trans OutPut Res)}
%%%% check transaction
%%%% The result is commit, abort
{Wait Res}
{System.show Res}
To avoid speculative computations, we offer a synchronization procedure to wait for locks on GS objects. If a user has a lock on a GS object say O
, all its local modifications on O
become global (broadcasted to all users). Here is an example of transaction that waits for Obj1
and Obj2
locks before performing the updates.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialise transactions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
proc{Trans Out}
% Synchronous waiting for locks on Obj1 Obj2
% if lock obtained -> ok
% else Trans aborted
{LocalStore waitlocks([Obj1 Obj2])}
{Obj1 inc(1)}
{Obj1 inc(~1)}
{Obj2 inc(~1)}
{Obj2 inc(2)}
{Obj1 inc(1)}
Out=state({Obj1 show($)})
end
OutPut % Output of Trans
Transid % Transaction Identifier
Res
in
{LocalStore trans(Trans OutPut ?Res)}
%%%% check transaction
%%%% The result is commit, abort
{Wait Res}
{System.show Res}
To delete object from the store is synchronous
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% delteing Obje2 %%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
proc{Delete}
Res in
{LocalStore deleteobj(Obj2 ?Res)}
{Wait Res}
{Show objectdeletionresult#Res}
end
{Delete}
%%%%%%%%%%%%%%%%%%%%%%%%%
To enhance the reliability of GS, users can choose a specific site where the new GS will be moved. A user can migrate the GS to a specific host. This is useful for load balancing or to reduce communication latency with current GS home site. The call {Movehere Module ?LS Proc}
migrates the GS from its current home site to the site where Movehere
is executed and returns the new reference to the store after migration. After the end of store migration, all dependencies with the home site are removed.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% migrate the global store
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{Movehere}
There is two condition to disconnect from GlobalStore: no disconnection durnig recovery phase and at least there is another Client alive.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% disconnect from GlobalStore %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{LocalStore disconnect(Res)}
{Wait Res}
if Res==true
then {Application.exit 0}
else
{Show 'disconnaction fails during recovery'}
end
%%%%%%%%%%%%%
<< Prev | - Up - | Next >> |