Getting started with Correlate



The following topics are discussed:


Testing: "hello world"

After you installed the jars, you can test it by writing the following evergreen. Open a new file with your favourite editor and type in the following:

// This is your first CORRELATE program
public active class Hello{
    public autonomous void sayIt(){
        System.out.println("Hello world !");
    }
}
Save this file as Hello.cor in a directory, e.g. /home/bert/examples/.

The next step is to compile the file. Make sure the CLASSPATH and PATH contain the correct values (see the readme file that is part of the Correlate distribution). Then type:

corc Hello.cor
If you typed no mistakes, the following files are generated in you directory:
Hello$Imp.class : bytecode
Hello$MyClass.class : bytecode
Hello.ast : parse information
Hello.class : bytecode
Hello.java : generated java code, do not edit !

The last step is running the program. To do this, we first create a property file that describes how the application should run. In our case, it looks like this:
correlate.runtime = correlate.meta.MetaRuntime
runtime = correlate.runtime.Main
main = Hello
At this momemt, the only line in this property file you should understand is the last one. This line defines the main class; i.e. the class from which the first object should be created. Note that the fully qualified name of the class (i.e. including package name) should be used here.

As soon as the property file has been created (lets call it "hello"), we can run the program as follows:

cor hello
The output should be something like:
Hello world !
Hello world !
Hello world !
...
You can stop the program by pressing ^C (CONTROL-C).

Now, what have we exactly created? The first line states we have an active class, so there can be interface operations and autonomous operations. Indeed, the next line defines one autonomous operation: sayIt() which simply continually prints something on the screen using the (passive) Java class System.

For more info, see Correlate in a NutShell and the Correlate syntax


to index

The producer-consumer example

We will now explain a second example, that is included in the Correlate-distribution. Compile it first with the corc command as before.

corc Producer.cor
You can then run it by typing the following (the current working directory is ${CORRELATE_HOME}/props) :
cor pc
This example shows a simple client-server interaction between a producer and a consumer.

//file: Consumer.cor
package examples.pc;

active class Consumer {
    private int count;
    public Consumer() {
        count = 1;
        System.out.println("Consumer " + self + " created.");
    }
    public void finalizeCorrelateObject() {
        super.finalizeCorrelateObject();
        System.out.println("Consumer " + self + " destroyed.");
    }
    public void consume(int p) throws IAmFullException {
        System.out.println("Consumer[" + count + "]" + self + " consumes " + p);
        count++;
    }
}
The active class Consumer models a simple server that consumes a fixed number of integer values. The Consumer class consists of three operations. The first is a simple default constructor that initializes the new object and print a message on the screen. The second operation, finalizeCorrelateObject(), is the destructor. It is called when the active object is destroyed. The last operation, consume(), is an interface operation that defines the external interface of the Consumer objects.

//file: Producer.cor
package examples.pc;

public active class Producer {
    int count;
    Consumer consumer;
    Producer() {
        System.out.println("Producer " + self + " : creating ...");
        consumer = new $ Consumer();
        System.out.println("Producer " + self + " : created.");
        count = 0;
    }
    autonomous void produce() precondition count < 10 {
         count++;
         try {
             consumer @ consume((int) (Math.random() * 10000));
         } catch (IAmFullException e) {
             System.out.println("Seeeeg");
         }
    }
}
The Producer class defines the client. Instances of this class are connected to a Consumer object and produce integer values that are consumed by the latter object.
The default constructor (which is called when you run the example) initializes a Producer and synchronously creates a new Consumer. A message is printed on the screen before and after the Consumer object is created. The autonomous operation produce() generates random numbers and sends these asynchronously to the consumer. A message is printed on the screen when the consumer throws an exception to indicate that it is full.

The output of the example should look like this:

Producer examples.pc.Producer@6fd65fef : creating ...
Consumer examples.pc.Consumer@52f65fef created.
Producer examples.pc.Producer@6fd65fef : created.
Consumer[1] examples.pc.Consumer@52f65fef consumes 5180
Consumer[2] examples.pc.Consumer@52f65fef consumes 3194
Consumer[3] examples.pc.Consumer@52f65fef consumes 3295
Consumer[4] examples.pc.Consumer@52f65fef consumes 9069
Consumer[5] examples.pc.Consumer@52f65fef consumes 3998
Consumer[6] examples.pc.Consumer@52f65fef consumes 4240
Consumer[7] examples.pc.Consumer@52f65fef consumes 9519
Consumer[8] examples.pc.Consumer@52f65fef consumes 3521
Consumer[9] examples.pc.Consumer@52f65fef consumes 3277
Consumer[10] examples.pc.Consumer@52f65fef consumes 2464


to index

The SOR application

The SOR demo program is a simple simulation that calculates the temperature of a rectangular plate with fixed temperatures on the edges.

It is an example of a numerical computation that can be solved in a distributed way. A plate has got initial temperatures on the edges. You want to know the temperature in each point of the plate. Therefore the heat equation (Laplace) must be solved. This is done by dividing the plate into a number of tiles, so called work units. Starting from the initial conditions of the plate (the temperatures on the edges), the work units solve the Laplace differential equation and pass the results to their neighbours. They again can solve the equation with the new inputs. In this way, you get the overal temperature of the plate in an iterative manner. There is a file called sor.properties, where you can change the setup, e.g. the number of worker units, the initial conditions, etc.

To start the sor demo (after it has been compiled of course):

cor sor
Distributed execution is handled in the section on metalevels.


to index

Tips for writing programs


to index

Adding a Metalevel

This section explains how you can run the examples with a metalevel.

Distribution

Correlate applications can run in a distributed environment, by adding a distribution metalevel. A simple example of such a metalevel is part of the Correlate distribution. This metaprogram can start either as a daemon or as an application launcher. An application launcher only differs from a daemon in the sense that it starts the main object of an application. The required setup for a distributed execution is to have one application launcher together with a number of daemons. This metaprogram requires JDK 1.2 because it used some serialization features in its implementation that are only supported in JDK1.2.

Before distributed execution can start, the names of the hosts that participate have to be recorded in the property files. Note that this is not a restriction of Correlate itself but only of that particular metaprogram. Therefore the two propertyfiles (one for the application launcher and one for the daemon) have to be completed. In the next example, we show the property files that allow the SOR application to run distributed on hosts multi.cs.kuleuven.ac.be and on media.cs.kuleuven.ac.be.

So you probably have to change the host.local and the list.host.others property to match machines in your own domain before you can run the demo. The former property defines the connection the distribution will be listening on, the latter gives a list of other connections to establish before starting.
After this, simply start the launcher on one machine and the daemon on the others.

The sor application now runs on the two machines. A similar approach can be applied to any Correlate application.

Reliability

An example of a reliability metalevel is also provided. It is a simple checkpointing algorithm. This algorithm periodically saves the state of all application objects to disk. After a crash, the application can be restarted from the most recent complete state.
Note: this metalevel works only for applications that never use synchronous interaction !

Start:

cor sor checkpointing
Restart from persistent state:
cor sor checkpointing-restart

Note that the checkpointing algorithm creates a new log file for each object and for each checkpoint. If the application is interrupted (for instance by a crash) in the interval during which a checkpoint was in progress, only an incomplete log of the global state is available. It is up to the user to remove these logfiles manually before the application is restarted. Otherwise, the restart algorithm will try to restart from the incomplete checkpoint and a deadlock will result. Note that this is not very difficult to do because the name of the logfiles contains the number of the checkpoint.

Distributed Reliability

The checkpointing algorithm is distribution independent. This means that a distribution metaprogram can be added transparently. It is even possible to start an application on a single host and later restart on multiple hosts (or vice versa).

Example property files are part of the Correlate distribution that reliably execute SOR on multiple hosts. These can be run just like a normal distributed application (i.e. one application launcher, multiple daemons).

Restart can happen as before on a single host, or distributed as follows:

For more info on writing metalevel protocols on your own, see Technical Report CW265 in the Publications section


to index