Alan Kaminsky Department of Computer Science Rochester Institute of Technology 4486 + 2220 = 6706
Home Page
[an error occurred while processing this directive]

4005-730 Distributed Systems
Grid Computing System Version 1

Prof. Alan Kaminsky
Rochester Institute of Technology -- Department of Computer Science
Adapted by Prof. Warren R. Carithers, 2010/12/15

Overview
The Grid Computing System
Software Requirements
Example Command Lines


Overview

Write a Java program for a simulated grid computing system. The program will include distributed objects for the various entities in the grid computing system, as well as a user client. The distributed objects will reside in multiple processes running on different host computers, and communicating with each other using Java remote method invocation (RMI). This version will assume there is only one client running at a time and that processes never fail.


The Grid Computing System

The Grid Computing System (GCS) provides CPU cycles as a public utility, like electricity. The GCS has a number of compute server objects. Each compute server does just one thing: it calculates a mathematical function of a double precision floating point number and returns the result.

A client can reserve a compute server in order to perform a computation on a series of numbers. After it reserves the compute server, the client specifies which mathematical function the compute server is to calculate. To do so, the client provides the server with a function object that implements interface Function:

    public interface Function
        {
	public String name();
        public double f (double x);
        }
The client then calls a method on the compute server to perform the calculation on a given number. The compute server calls the function object's f() method on that number and returns the result to the client. The client repeats this for as many numbers as desired. Then the client releases the compute server, making the compute server available for other clients to use.

For example, if the client wants the compute server to calculate the sine of each number, the client provides the compute server with a function object that is an instance of this class:

    public class SineFunction
        implements Function
        {
        public String name()
            {
            return "sin";
            }
        public double f (double x)
            {
            return Math.sin (x);
            }
        }

The GCS also lets a client compose several functions together. For example, suppose the client wants to compute three functions, a, b, and c, on each number x to produce the result y = a(b(c(x))). The client sets up a list of function objects, one for each individual function. The client also sets up a list of compute server objects that will be used to calculate each individual function. The client reserves each compute server in the list and specifies each compute server's function object as before. The client then goes back and tells each compute server in the list what the next compute server is (except the last compute server has no successor). When the client calls a method on the first compute server to perform the calculation on a given number, the first compute server calls the second compute server, the second compute server calls the third compute server, and so on until the last compute server is reached. Then each compute server performs its calculation and returns the result to the previous compute server; the first compute server returns the ultimate result to the client. The client repeats this for as many numbers as desired. Then the client releases each of the compute servers, making the compute servers available for other clients to use.

Here is an example of a client using the GCS to calculate the square of the natural logarithm of the sine of a series of numbers: y = sqr(log(sin(x))). The compute server objects are named A, B, and C.

Client                     Compute Server A               Compute Server B               Compute Server C
   |                              |                              |                              |
   |reserve()                     |                              |                              |
   |----------------------------->|                              |                              |
   |                        return|                              |                              |
   |<-----------------------------|                              |                              |
   |reserve()                     |                              |                              |
   |------------------------------------------------------------>|                              |
   |                              |                        return|                              |
   |<------------------------------------------------------------|                              |
   |reserve()                     |                              |                              |
   |------------------------------------------------------------------------------------------->|
   |                              |                              |                        return|
   |<-------------------------------------------------------------------------------------------|
   |setFunction(sqr)              |                              |                              |
   |----------------------------->|                              |                              |
   |                        return|                              |                              |
   |<-----------------------------|                              |                              |
   |setFunction(log)              |                              |                              |
   |------------------------------------------------------------>|                              |
   |                              |                        return|                              |
   |<------------------------------------------------------------|                              |
   |setFunction(sin)              |                              |                              |
   |------------------------------------------------------------------------------------------->|
   |                              |                              |                        return|
   |<-------------------------------------------------------------------------------------------|
   |setSuccessor(B)               |                              |                              |
   |----------------------------->|                              |                              |
   |                        return|                              |                              |
   |<-----------------------------|                              |                              |
   |setSuccessor(C)               |                              |                              |
   |------------------------------------------------------------>|                              |
   |                              |                        return|                              |
   |<------------------------------------------------------------|                              |
   |                              |                              |                              |
   |apply(0.5)                    |                              |                              |
   |----------------------------->|                              |                              |
   |                              |apply(0.5)                    |                              |
   |                              |----------------------------->|                              |
   |                              |                              |apply(0.5)                    |
   |                              |                              |----------------------------->|
   |                              |                              |                  return 0.479| sin(0.5) = 0.479
   |                              |                              |<-----------------------------|
   |                              |                 return -0.735|                              | log(0.479) = -0.735
   |                              |<-----------------------------|                              |
   |                  return 0.540|                              |                              | sqr(-0.735) = 0.540
   |<-----------------------------|                              |                              |
   |                              |                              |                              |
   |apply(1.0)                    |                              |                              |
   |----------------------------->|                              |                              |
   |                              |apply(1.0)                    |                              |
   |                              |----------------------------->|                              |
   |                              |                              |apply(1.0)                    |
   |                              |                              |----------------------------->|
   |                              |                              |                  return 0.841| sin(1.0) = 0.841
   |                              |                              |<-----------------------------|
   |                              |                 return -0.173|                              | log(0.841) = -0.173
   |                              |<-----------------------------|                              |
   |                  return 0.030|                              |                              | sqr(-0.173) = 0.030
   |<-----------------------------|                              |                              |
   |                              |                              |                              |
   |release()                     |                              |                              |
   |----------------------------->|                              |                              |
   |                        return|                              |                              |
   |<-----------------------------|                              |                              |
   |release()                     |                              |                              |
   |------------------------------------------------------------>|                              |
   |                              |                        return|                              |
   |<------------------------------------------------------------|                              |
   |release()                     |                              |                              |
   |------------------------------------------------------------------------------------------->|
   |                              |                              |                        return|
   |<-------------------------------------------------------------------------------------------|
   |                              |                              |                              |

In order to slow the system down so we humans can watch its operation, each compute server method adds a two-second delay before returning.


Software Requirements

    Function Interface
     
  1. The system must have an interface representing a function to be calculated.
     
  2. The function interface must have a method that returns the name of the function, a String.
     
  3. The function interface must have a method for calculating the function.
     
    1. The method must have an argument, which is a double precision floating point number.
       
    2. The method must return the result of applying the function to the argument, which is a double precision floating point number.
       
  4. The function interface must be written as follows, and it must not be in a package:
        public interface Function
            {
            public String name();
            public double f (double x);
            }
    
    Compute Server Object
     
  5. The system must have a remote object representing each compute server.
     
  6. When created, a compute server object must bind itself with a given name into the Registry Server running at a given host and a given port.
     
  7. An instance of the compute server object must be run by typing this command line:
     
    java Start ComputeServer <host> <port> <name>
     
    Note: This means that the compute server object's class must be named ComputeServer, this class must not be in a package, and this class must define the appropriate constructor for the Start program.
     
  8. A compute server object's constructor must throw an exception and must not bind itself into the Registry Server if there are any of the following problems with the command line arguments. The exception's detail message must be a meaningful explanation of the problem.
  9. The compute server object must have a method to reserve the compute server for a calculation session.
     
    1. If this compute server object is part of a calculation session, this method must throw an exception with a meaningful error message.
       
  10. The compute server object must have a method to specify the function for the calculation to be performed.
     
    1. The method must have an argument giving a function object.
       
    2. If this compute server object is not part of a calculation session, this method must throw an exception with a meaningful error message.
       
  11. The compute server object must have a method to specify the successor compute server.
     
    1. The method must have an argument giving a reference to the successor compute server.
       
    2. If this compute server object is not part of a calculation session, this method must throw an exception with a meaningful error message.
       
  12. The compute server object must have a method for calculating the compute server's function as specified when the compute server was reserved.
     
    1. The method must have an argument, which is a double precision floating point number.
       
    2. The method must return the result of applying the function to the argument, which is a double precision floating point number.
       
    3. If this compute server object is not part of a calculation session, this method must throw an exception with a meaningful error message.
       
  13. The compute server object must have a method to release the compute server from a calculation session.
     
    1. If this compute server object is not part of a calculation session, this method must throw an exception with a meaningful error message.
       
  14. The compute server object must behave as specified above under "The Grid Computing System."
     
  15. A compute server object must display its state at all times; specifically:
     
    1. Immediately after the compute server object is created, and whenever the compute server leaves a calculation session, the compute server object must print the following line on the console:
       
          Compute Server <name> -- available
       
      where <name> is replaced with the name of the compute server.
       
    2. Whenever the compute server enters a calculation session, the compute server object must print the following line on the console:
       
          Compute Server <name> -- reserved
       
      where <name> is replaced with the name of the compute server.
       
    3. Whenever the compute server's function is specified, the compute server object must print the following line on the console:
       
          Compute Server <name> -- function: <func>
       
      where <name> is replaced with the name of the compute server and <func> is replaced with the name of the function.
       
    4. Whenever the compute server's successor is specified, the compute server object must print the following line on the console:
       
          Compute Server <name> -- successor: <succ>
       
      where <name> is replaced with the name of the compute server and <succ> is replaced with the name of the compute server's successor.
       
    5. Whenever the compute server starts to perform a calculation, before performing the actual calculation, the compute server object must print the following line on the console:
       
          Compute Server <name> -- f(<arg>)
       
      where <name> is replaced with the name of the compute server and <arg> is replaced number upon which to perform the calculation.
       
    6. Whenever the compute server finishes performing a calculation and is about to return the calculated function value, the compute server object must print the following line on the console:
       
          Compute Server <name> -- <func>(<arg>) = <val>
       
      where <name> is replaced with the name of the compute server, <func> is replaced with the name of the function the compute server is calculating, <arg> is replaced with the function's argument value, and <val> is replaced with the function's return value.
       
  16. Each of the above compute server methods must add a two-second delay after doing all its work and before returning.
     
  17. The compute server object must not print anything other than what is specified above.
     
    Client Program
     
  18. The system must have a compute client main program to perform calculations on a series of numbers.
     
  19. The compute client program must be run by typing this command line:
     
    java ComputeClient <host> <port> <func> <name> [ <func> <name> ... ]
     
    Note: This means that the compute client program's class must be named ComputeClient, and this class must not be in a package.
     
  20. The compute client program must print an error message and terminate without starting a computation session if there are any of the following problems with the command line arguments. The error message must include a meaningful explanation of the problem. The error message may include an exception stack trace.
  21. The compute client program must behave as specified above under "The Grid Computing System."
     
  22. The compute client program must read from the standard input zero or more numbers upon which to perform the calculations.
     
  23. Each line of the compute client program's standard input must consist of a single double precision floating point number.
     
  24. If the compute client program cannot parse a line of the standard input as a double precision floating point number, the compute client program must shut down the computation session, print an error message, and terminate. The error message must include a meaningful explanation of the problem. The error message may include an exception stack trace.
     
  25. After obtaining the result of the calculation on each number read from the standard input, the compute client program must print the following line on the console:
     
        f(<arg>) = <val>
     
    where <arg> is replaced with the number read from the standard input and <val> is replaced with the result of the calculation.
     
  26. If an exception occurs and the above requirements do not state how to handle the exception, the compute client program must shut down the computation session if necessary, print an error message, and terminate. The error message must include a meaningful explanation of the problem. The error message may include an exception stack trace.
     
  27. The compute client program must not print anything other than what is specified above.


Server Source Code


Client Source Code


Example Command Lines

To perform the example calculation session depicted in the above timeline under "The Grid Computing System," run the following commands, each in a separate process on the same machine.

  1. Run the Registry Server (script: runregistry).

    $ runregistry

    #!/bin/bash
    java \
    -classpath /home/fac/ark/public_html/cscl/lib \
    Start edu.rit.ds.registry.RegistryServer

  2. Set up a security policy for the Compute Server (policy file: policy).

    grant codebase "file:/home/fac/wrc/www/courses/common/ds/gcs/gcs01/"
        {
        permission java.security.AllPermission;
        };
    grant codebase "file:/home/fac/ark/public_html/cscl/lib/"
        {
        permission java.security.AllPermission;
        };

  3. Run several instances of the Compute Server, specifying the security policy (script: runcomputeserver).

    $ runcomputeserver A
    $ runcomputeserver B
    $ runcomputeserver C

    #!/bin/bash
    java \
    -classpath /home/fac/wrc/www/courses/common/ds/gcs/gcs01:/home/fac/ark/public_html/cscl/lib \
    -Djava.security.policy=policy \
    Start ComputeServer localhost 9901 $1

  4. Set up a security policy for the Compute Client (policy file: client/policy).

    grant codebase "file:/home/fac/wrc/www/courses/common/ds/gcs/gcs01/client/"
        {
        permission java.security.AllPermission;
        };
    grant codebase "file:/home/fac/ark/public_html/cscl/lib/"
        {
        permission java.security.AllPermission;
        };

  5. Set up a web server so that class files in the client's class path can be downloaded from a URL. This is called the codebase URL.
     
  6. Run the Compute Client, specifying the security policy and the client's codebase URL (script: client/runclient). Specify function class names and compute server names on the command line. Type arguments upon which to calculate the function. Hit CTRL-D (end-of-file) when done.

    $ runclient SqrFunction A LogFunction B SineFunction C
    0.5
    1.0
    CTRL-D

    #!/bin/bash
    java \
    -classpath /home/fac/wrc/www/courses/common/ds/gcs/gcs01/client:/home/fac/wrc/www/gcs/gcs01:/home/fac/ark/public_html/cscl/lib \
    -Djava.security.policy=policy \
    -Djava.rmi.server.codebase=http://www.cs.rit.edu/~wrc/gcs/gcs01/client/ \
    ComputeClient localhost 9901 $*
    

Compute Server A prints the following on the console (the floating point numbers may print with additional digits of precision):

Compute Server A -- available
Compute Server A -- reserved
Compute Server A -- function: sqr
Compute Server A -- successor: B
Compute Server A -- f(0.5)
Compute Server A -- sqr(-0.735) = 0.540
Compute Server A -- f(1.0)
Compute Server A -- sqr(-0.173) = 0.030
Compute Server A -- available

Compute Server B prints the following on the console (the floating point numbers may print with additional digits of precision):

Compute Server B -- available
Compute Server B -- reserved
Compute Server B -- function: log
Compute Server B -- successor: C
Compute Server B -- f(0.5)
Compute Server B -- log(0.479) = -0.735
Compute Server B -- f(1.0)
Compute Server B -- log(0.841) = -0.173
Compute Server B -- available

Compute Server C prints the following on the console (the floating point numbers may print with additional digits of precision):

Compute Server C -- available
Compute Server C -- reserved
Compute Server C -- function: sin
Compute Server C -- f(0.5)
Compute Server C -- sin (0.5) = 0.479
Compute Server C -- f(1.0)
Compute Server C -- sin (1.0) = 0.841
Compute Server C -- available

The compute client program prints the following on the console (the floating point numbers may print with additional digits of precision):

f(0.5) = 0.540
f(1.0) = 0.030

[an error occurred while processing this directive]
Alan Kaminsky Department of Computer Science Rochester Institute of Technology 4486 + 2220 = 6706
Home Page
Copyright © 2006 Alan Kaminsky. All rights reserved. Last updated 13-Dec-2006. Please send comments to ark­@­cs.rit.edu.
Adaptations last updated 2010/12/15 by Warren R. Carithers.