signature REMOTE structure Remote : REMOTE
This structure provides support for the implementation of distributed applications. This includes exporting values from and importing values into sites, performing remote function application and starting a new site. See the distribution overview for an introduction to the distribution facilities provided by Alice.
Communication between sites is performed by cloning data structures. Cloning is defined by pickling.
See also: COMPONENT_MANAGER, Url, Pickle, Lock.Sync
import structure Remote from "x-alice:/lib/distribution/Remote" import signature REMOTE from "x-alice:/lib/distribution/REMOTE-sig"
signature REMOTE = sig type ticket = string exception Proxy of exn exception SitedArgument exception SitedResult exception Protocol of string exception Ticket exception Exit val proxy : ('a -> 'b) -> ('a -> 'b) val offer : package -> ticket val take : ticket -> package val eval : string * Component.t -> package val run : string * Component.t -> package functor Proxy (signature S structure X : S) : S functor Offer (signature S structure X : S) : (val ticket : ticket) functor Take (val ticket : ticket signature S) : S functor Eval (val host : string signature S functor F : COMPONENT_MANAGER -> S) : S functor Run (val host : string signature S functor F : COMPONENT_MANAGER -> S) : S end
The type of tickets representing offered values. Tickets are short strings suitable for communication, for instance, over voice lines or by email. Tickets are suitable for parsing as URLs.
indicates that a ticket was not well-formed or referred to a site or value that could not be accessed.
indicates that a call through a proxy has failed. The argument exception describes the specific cause of failure.
the former two exceptions indicate that the argument or result of a call to a proxy, or to eval or run contained a sited value. The third exception indicates an internal protocol error during execution of excute or a proxy call, where the string describes the error condition in text form. For proxy calls, these exceptions are never raised directly, but occur only as the argument of a Proxy exception.
indicates that a remote process has called OS.Process.exit before evaluation of its root component has finished.
returns a proxy for f. The proxy differs from f in that:
the argument to the proxy is cloned before f is applied to it; it may not contain sited values;
the result of f (either a value or an exception) is cloned before it is delivered to the caller; it may not contain sited values;
whenever the proxy itself is cloned, only a reference to the running site is cloned which does not contain a clone of f;
when the proxy is applied, no matter on which site, this causes f to be applied on the site on which the proxy was created, if necessary by transferring argument and result between the sites.
The cloning performed when applying proxies implies that any future in the argument value or result is requested. That may raise an exception due to a failed future, which then becomes the result of the call. In either case, this is considered regular execution of the proxy call.
But proxy calls may also fail, for a number of reasons. In each case, the exception Proxy is raised to indicate failed execution of the call, with the actual cause as an argument. The following causes are possible:
The argument to the proxy contains a sited value. In that case, Proxy(SitedArgument) will be raised.
The result of applying f (a value or raised exception) contains a sited value, or it contains a failed future that carries an exception with a sited value or another failed future. In all cases, Proxy(SitedResult) will be raised. (Secondary failed futures are captured to prevent divergence in the case of circular data structures.)
The process in which the proxy was created has terminated. In this case, Proxy(Ticket) will be raised.
A protocol failure occurs in the lower communication layers. In this case, Proxy(Protocol s) will be raised, with s describing the error condition. One possible cause is that the remote process terminates before the call returns (in particular, this can occur when the call itself triggers termination of the remote process).
An I/O problem occurs in the lower communication layers. In this case, Proxy(Io args) will be raised, with args carrying further information. Usually, this means that the process that exported the proxy is no longer alive.
Other causes for raising Proxy are possible.
returns a wrapper of structure X where all fields of function type are replaced by a proxy for the respective function. A function that returns a function will return a proxy, respectively (i.e. the wrapping is recursively performed for curried functions).
If X is a functor, then a proxy for the functor is created. When the functor is applied, the resulting module will be wrapped recursively (i.e. the wrapping is recursively performed for curried functors and any resulting structure).
Example:
Proxy (signature S = (val x : int val f : int -> int val g : int -> int -> int) structure X = (val x = 5 fun f n = n + 1 fun f n m = n + m))
returns a structure that is equivalent to
struct val x = 5 val f = proxy (fn n => n + 1) val g = proxy (fn n => proxy (fn m => n + m)) end
Similarly,
Proxy (signature S = fct () -> (val x : int val f : int -> int -> int) structure X = fct () => (val x = 5 fun f n m = n + m))
returns a proxy for a functor equivalent to
fct () => (val x = 5 val f = proxy (fn n => proxy (fn m => n + m)))
Note that structure fields of non-function type will not be wrapped, even if they contain function values. For example,
Proxy (signature S = (val p : (int -> int) * (int -> int)) structure X = (val p = (fn n => n, fn n => n + 1)))
returns X unchanged.
makes package available to other sites for taking. Returns a ticket suitable for take or Take. Raises Sited if the package contains sited values. An offered package can be taken any number of times. If the package contains mutable data, then each take will return a clone of a snapshot of the package made when offer is executed.
imports the data structure denoted by ticket, which must have been created by offer or Offer. Raises Ticket if the ticket is invalid or the site on which it was created no longer exists. Raises IO.Io if retrieving the package fails for other reasons.
makes module X available to other sites for taking with signature S. Returns a ticket suitable for take or Take. Equivalent to
(val ticket = offer (pack X : S))
imports the module denoted by ticket, which must have been created by offer or Offer, under a sub-signature of S. Raises Ticket if the ticket is invalid or the site on which it was created no longer exists. Raises Package.Mismatch if the module was not exported with a signature matching S. Raises IO.Io if retrieving the module fails for other reasons. Equivalent to
unpack (take ticket) : S
create a new site on host using
Like proxy calls, remote execution may fail for a number of reasons:
The component contains a sited value. In that case, SitedArgument will be raised.
The remote process calls OS.Process.exit before evaluation of the component was finished. In this case, Exit is raised.
The export of the component contains a sited value after evaluation on the remote site, or it contains a failed future that carries an exception with a sited value or another failed future. In all cases, SitedResult will be raised. (Secondary failed futures are captured to prevent divergence in the case of circular data structures.)
A protocol failure occurs in the lower communication layers. In this case, Protocol s will be raised, with s describing the error condition.
An I/O problem occurs in the lower communication layers. In this case, Io args will be raised, with args carrying further information.
With eval, the remote process will exit after evaluation of the component, regardless of any concurrent processes that may have been spawned by evaluation. With run, the remote process stays alive after the result is returned to the caller, i.e. the process is not terminated automatically. This allows concurrent threads to continue running; in particular, it enables the remote process to create proxies and return them to the caller who can therewith call into the remote process later. To terminate the process, an explicit call to OS.Process.exit on the remote site is required. If evaluation of the component raises an exception, the process is terminated in both cases.
Note that the ssh command must be available on the local site, you must be able to login on the remote site via SSH without entering a password (e.g. by using an SSH daemon), and the Alice System's bin directory must be in PATH on the remote site. On Linux, the latter can optionally be achieved by setting ALICE_REMOTE_PATH=<alice-bin-dir> into your ~/.ssh/environment file, if enabled. If that is not possible, you can fall back to having a script named aliceremote in your remote home directory, which sets paths appropriately and forwards its arguments to the alicerun command of the Alice System.
If the environment variable ALICE_REMOTE_LOG is set on the remote machine then its value will be interpreted as a file name and some logging information about the remote execution will be written to the file (without truncating it).
construct a component with export signature S from
F and transfer a clone of it to a newly created site
on host using
let structure C = Component.Create (signature S = S structure F = F) in unpack (eval (host, C.component)) : S end
and
let structure C = Component.Create (signature S = S structure F = F) in unpack (run (host, C.component)) : S end
Here is an example of a simplistic program that creates a component to read the content of a file on a remote site. Note how the mobile component refers to dynamically acquired data, namely the respective file name:
import structure Url from "x-alice:/lib/system/Url" import structure Remote from "x-alice:/lib/distribution/Remote" import signature TEXT_IO from "x-alice:/lib/system/TEXT_IO-sig" import signature COMPONENT_MANAGER from "x-alice:/lib/system/COMPONENT_MANAGER-sig" structure Main = struct val (hostname, filename) = case CommandLine.arguments () of [s1, s2] => (s1, s2) | _ => (TextIO.output (TextIO.stdErr, "usage: fetch\n"); OS.Process.exit OS.Process.failure) functor Comp (CM : COMPONENT_MANAGER) = let structure TextIOComp = CM.Link (val url = Url.fromString "x-alice:/lib/system/TextIO" signature S = (structure TextIO : TEXT_IO)) open TextIOComp val file = TextIO.openIn filename in (val content = TextIO.inputAll file before TextIO.closeIn file) end structure Result = Remote.Eval (val host = hostname signature S = (val content : string) structure F = Comp) val _ = TextIO.print Result.content val _ = OS.Process.exit OS.Process.success end