wiki:JavaParty/ReplicatedObjects

Transparent Replicated Objects

Since JavaParty 1.9.4

Local and remote objects

Before introducing transparent replicated objects, let’s first have a look at local and remote objects. Remote objects are created at a particular node and can migrate if required. They are used at their current location and are accessible throughout the system by remote references. Local objects are bound to the node they were created on, so they are locally accessible in a fast and direct manner. Passing a local object in a remote call causes the object to be copied.

Replicated objects

Replicated objects are locally accessible on all nodes, each node has exactly one copy of it. These copies are held consistent by using synchronization. In the following paragraphs, we’ll use the replicated class P as an example:

public replicated class P {
    public P() {...} // constructor

    int[] x; // instance variable
    String l; // reference to a local object
    R r; // reference to a remote object
    P p; // another reference to a remote object

    static R sr; // static variable
    static P sp; // static variable

    void foo() {...} // instance method
    static void sfoo() { ... } // class method
}

Replicated objects are simply created by using the constructor new P() which returns a reference to the local replicate. This reference is a real Java reference to an object of class P with all its instance variables and methods. There is no proxy object “hiding” the replicate, no rewrite of field access to getters and setters, and no copying of referenced objects. Replicates are implicitly created on all nodes of the distributed virtual machine.

Constructing a replicated object creates exactly one replicate per virtual machine and returns a local reference to it. The behavior of replicated objects is semi local and semi remote: They are only locally accessible like local objects but passed as reference in a remote call like remote objects. That is, the reference to the replicate is replaced by the corresponding local reference during the remote call. Replicates on other nodes are only accessible through a remote object.

Synchronization

Recall that access to a replicate happens in a direct and local manner: Both read and write operations access and modify respectively the state of the local replicate. Changes to the local replicate temporary destroy consistency, so the consistency of the replicates must be restored by synchronization. In pure Java, synchronization is always exclusive - an approach that’s not feasible for a remote environment: If only one access was allowed simultaneously, no parallelism would be possible and if all other replicates had to be locked before accessing the local replicate, the access would no longer be local. Existing synchronization primitives don’t support a protocol that allows for multiple readers in the presence of a single writer. JavaParty introduces replicated classes that allow for collective replication of local objects.

Parallel, distributed read access may be used to synchronize multiple readers. A shared lock can be obtained by using a synchronized block or method:

shared synchronized(p) { ... }
replicated class P {
    shared synchronized int getX() { ... }
}

Exclusive, local write access with a following state update of all replicates may be used to synchronize a single writer. An exclusive lock can be obtained in the same way as an shared lock:

exclusive synchronized(p) { ... }
exclusive synchronized void setX(int x) { ... }

Unlike Java synchronization, the synchronization of replicated objects must always happen at the replicated object that‘s currently read or modified. State updates take place before releasing an exclusive lock for the object that was used for synchronization. Please note that exclusive synchronization is quite expensive compared to shared synchronization, because exclusive synchronization has to use communication.

Collective modification

Replicated objects also support parallel operations like multiple collective writers. In order to automatically merge the changes, parallel modifications of the state of a replicated object must not overlap. That is, each activity may only change a disjoint part of the overall state. After the modification, the concurrent modifications are merged to a new consistent state.

Collective modifications are marked as synchronized blocks:

collective synchronized(p) {
    // your updates here
}

Collective synchronization is achieved by synchronizing all replicates in parallel. The collective synchronized block will not be entered until a thread has been synchronized with each local replicate. Remember that this also requires to assign a thread to each node, otherwise the system will end up in a deadlock. Before the collective synchronized block is left, all concurrent changes are merged. Everything that has been discussed so far is summarized in the following example:

P p = new P(); // object creation
r.foo(p); // argument passing
p.foo(); // method call

shared synchronized(p) { // shared read access
    System.out.println(p.x[0]);
}
exclusive synchronized(p) { // exclusive write access
    p.l = "Hello World!";
}
// forall n {0..N}
collective synchronized(p) { // collective modification
    p.x[n] = computeX(n);
}

At a particular time, a replicated object may be synchronized either shared / exclusive or collectively at all replicates. Be warned that mixing collective and shared / exclusive synchronization is likely to lead to a deadlock.

Signalizing

In shared or exclusive synchronized blocks, the wait() statement can be used to wait for a change in state. Only in an exclusive synchronized block, a signal may be sent to all replicates using the notifyAll() statement. No sending of signals is allowed in shared synchronized blocks and neither sending nor waiting for signals is allowed in collective synchronized blocks.

Last modified 11 years ago Last modified on Jan 17, 2007 10:53:50 AM