The following topics are discussed:
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.corIf 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 = HelloAt 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 helloThe 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
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.corYou can then run it by typing the following (the current working directory is ${CORRELATE_HOME}/props) :
cor pcThis 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.
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
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 sorDistributed execution is handled in the section on metalevels.
// This is an example of a classic main Class
public active class MainClass{
public MainClass(){
// here you can create objects and do
// some initialisation
System.out.println("Hello world !");
//delete the main object
delete @ self;
}
}
Note that you still have to hit ^C to get
your prompt back.
// deadlock example: the autonomous function calls a function of
// the same object in a synchronous way.
// As a result, they wait for each other
public active class Hello {
public void helloAgain() {
System.out.println("Hello again");
}
public autonomous void sayIt() {
System.out.println("Hello World !");
self $ helloAgain();
delete @ self;
}
}
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.
# distrib-initiator runtime=meta.distribution.Initiator list.singletons=correlate.nameserver.NameServer host.local=multi.cs.kuleuven.ac.be:10234 list.host.others=media.cs.kuleuven.ac.be:10234
# distrib-daemon runtime=meta.distribution.Daemon list.singletons=correlate.nameserver.NameServer host.local=media.cs.kuleuven.ac.be:10234 list.host.others=multi.cs.kuleuven.ac.be:10234
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.
cor sor distrib-initiator
cor sor distrib-daemon
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 checkpointingRestart 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.
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).
cor sor checkpointing distrib-initiator
cor sor distrib-daemon
Restart can happen as before on a single host, or distributed as follows:
cor sor checkpointing-restart distrib-initiator
cor sor distrib-daemon
For more info on writing metalevel protocols on your own, see Technical Report CW265 in the Publications section