Group communication is a crucial feature for high-performance and Grid computing. While previous works and libraries proposed such a characteristic (e.g. MPI, or object-oriented frameworks), the use of groups imposed specific constraints on programmers, for instance the use of dedicated interfaces to trigger group communications.
We aim at a more flexible mechanism. We propose a scheme where, given a Java class, one can initiate group communications using the standard public methods of the class together with the classical dot notation; in that way, group communications remains typed.
In order to ease the use of the group communication, we provide a
set of static methods on the ProActiveGroup
class and a
set of methods on the Group
interface.
Here, a short compilation about the syntax and some method used in the Group Communication API is presented. More informations follow.
// created at once, // with parameters specified in params, // and on the nodes specified in nodes A ag1 = (A) ProActiveGroup.newGroup( 'A', params, [nodes]); // A general group communication without result // A request to foo is sent in parallel to all active objects // in the target group (ag1) ag1.foo(...); // A general group communication with a result V vg = ag1.bar(...); // vg is a typed group of 'V': operation // below is also a collective operation // triggered on results vg.f1();
Any object that is reifiable has the ability to be included in a
group. Groups are created using the static method
ProActiveGroup.newGroup
. The common superclass for all
the group members has to be specified, thus giving the group a minimal
type.
Let us take a standard Java class:
class A { public A() {} public void foo (...) {...} public V bar (...) {...} ... }
Here are examples of some group creation operations:
// Pre-construction of some parameters: // For constructors: Object[][] params = {{...} , {...} , ... }; // Nodes to identify JVMs to map objects Node[] nodes = { ... , ..., ... }; // Solution 1: // create an empty group of type 'A' A ag1 = (A) ProActiveGroup.newGroup('A'); // Solution 2: // a group of type 'A' and its members are // created at once, // with parameters specified in params, // and on the nodes specified in nodes A ag2 = (A) ProActiveGroup.newGroup('A', params, nodes); // Solution 3: // a group of type 'A' and its members are // created at once, // with parameters specified in params, // and on the nodes directly specified A ag3 = (A) ProActiveGroup.newGroup('A', params[], {rmi://globus1.inria.fr/Node1, rmi://globus2.inria.fr/Node2});
Elements can be included into a typed group only if their class equals or extends the class specified at the group creation. For example, an object of class B (B extending A) can be included to a group of type A. However based on Java typing, only the methods defined in the class A can be invoked on the group.
The typed group representation we
have presented corresponds to the functional view of groups of objects. In
order to provide a dynamic management of groups, a second and
complementary representation of a group has been designed. In order to
manage a group, this second representation must be used instead. This
second representation, the management
representation, follows a more standard pattern for grouping
objects: the Group
interface.
We are careful to have a strong coherence between both
representations of the same group, which implies that modifications
executed through one representation are immediately reported on the other
one. In order to switch from one representation to the other, two methods
have been defined : the static method named
ProActiveGroup.getGroup
, returns the Group form
associated to the given group object; the method
getGroupBytype
defined in the Group
interface does the opposite.
Below is an example of when and how to use each representation of a group:
// definition of one standard Java object // and two active objects A a1 = new A(); A a2 = (A) ProActive.newActive('A', paramsA[], node); B b = (B) ProActive.newActive('B', paramsB[], node); // Note that B extends A // For management purposes, get the representation // as a group given a typed group, created with // code on the left column: Group gA = ProActiveGroup.getGroup(ag1); // Now, add objects to the group: // Note that active and non-active objects // may be mixed in groups gA.add(a1); gA.add(a2); gA.add(b); // The addition of members to a group immediately // reflects on the typed group form, so a method // can be invoked on the typed group and will // reach all its current members ag1.foo(); // the caller of ag1.foo() may not belong to ag1 // A new reference to the typed group // can also be built as follows A ag1new = (A) gA.getGroupByType();
The particularity of our group communication mechanism is that the result of a typed group communication is also a group. The result group is transparently built at invocation time, with a future for each elementary reply. It will be dynamically updated with the incoming results, thus gathering results. Nevertheless, the result group can be immediately used to execute another method call, even if all the results are not available. In that case the wait-by-necessity mechanism implemented by ProActive is used.
// A method call on a group, returning a result V vg = ag1.bar(); // vg is a typed group of 'V': operation // below is also a collective operation // triggered on results vg.f1();
As said in the Group creation section, groups whose type is based on final classes or primitive types cannot be built. So, the construction of a dynamic group as a result of a group method call is also limited. Consequently, only methods whose return type is either void or is a 'reifiable type', in the sense of the Meta Object Protocol of ProActive, may be called on a group of objects; otherwise, they will raise an exception at run-time, because the transparent construction of a group of futures of non-reifiable types fails.
To take advantage with the asynchronous remote method call model of
ProActive, some new synchronization mechanisms have been added. Static
methods defined in the ProActiveGroup
class enable to
execute various forms of synchronisation. For instance:
waitOne
, waitN
,
waitAll
, waitTheNth
,
waitAndGet
. Here is an exemple:
// A method call on a typed group V vg = ag1.bar(); // To wait and capture the first returned // member of vg V v = (V) ProActiveGroup.waitAndGetOne(vg); // To wait all the members of vg are arrived ProActiveGroup.waitAll(vg);
Regarding the parameters of a method call towards a group of objects, the default behaviour is to broadcast them to all members. But sometimes, only a specific portion of the parameters, usually dependent of the rank of the member in the group, may be really useful for the method execution, and so, parts of the parameter transmissions are useless. In other words, in some cases, there is a need to transmit different parameters to the various members.
A common way to achieve the scattering of a global parameter is to use the rank of each member of the group, in order to select the appropriate part that it should get in order to execute the method. There is a natural traduction of this idea inside our group communication mechanism:the use of a group of objects in order to represent a parameter of a group method call that must be scattered to its members.
The default behaviour regarding parameters passing for method call
on a group, is to pass a deep copy of the group of type P to all members.
Thus, in order to scatter this group of elements of type P instead, the
programmer must apply the static method setScatterGroup
of the ProActiveGroup
class to the group. In order to
switch back to the default behaviour, the static method
unsetScatterGroup
is available.
// Broadcast the group gb to all the members // of the group ag1: ag1.foo(gb); // Change the distribution mode of the // parameter group: ProActiveGroup.setScatterGroup(gb); // Scatter the members of gb onto the // members of ag1: ag1.foo(gb);
© 2001-2007 INRIA Sophia Antipolis All Rights Reserved