The FreePastry Tutorial.

This tutorial is designed to get you cooking quickly with the FreePastry API and software toolkit.

Version @tutorial_version@; @tutorial_date@. For FreePastry version @freepastry_version@. Maintained by @maintainer@.



Lesson 4

Running multiple nodes in the same JVM.

Download the tutorial files: DistTutorial.java (changed from Lesson 3!!!), MyApp.java, MyMsg.java into a directory called rice/tutorial/lesson4/.

This tutorial will show you how to create and run multiple FreePastry nodes within the same JVM. We will continue to use the Socket transport layer. This tutorial is very simple, all we will be doing is modifying lesson 3 to have multiple nodes.
Let's start with the changes to MyApp. We are going to make it keep a reference to the Node with a member variable named node. It will become apparent later in this tutorial.

  protected Node node;
In the constructor:
    this.node = node;
And here is the getter:
  public Node getNode() {
    return node;
  }
Now we will look at the changes to DistTutorial. We have a member variable apps that will keep track of the list of apps.
  Vector apps = new Vector();
We modify the constructor to take in how many nodes we wish to create:
  public DistTutorial(int bindport, InetSocketAddress bootaddress, int numNodes, Environment env) throws Exception {
After constructing the PastryNodeFactory we create a loop to construct the nodes, and add them to our apps Vector.
    for (int curNode = 0; curNode < numNodes; curNode++) {
	    
	    ...
	    
	    apps.add(app); 
    }
When routing messages, we have created a subloop to do so for each app in the system:
      // for each app
      Iterator appIterator = apps.iterator();
      while(appIterator.hasNext()) {
        MyApp app = (MyApp)appIterator.next();
        
        ...
        
      }
Note that we eliminated this code, because it is no longer important to not route if we are the bootstrap.
    // as long as we're not the first node
    if (bootHandle != null) {
In the send direct loop we use our getter MyApp.getNode(). This prevents us from having to remember a parallel data structure for the Nodes.
    // for each app
    Iterator appIterator = apps.iterator();
    while(appIterator.hasNext()) {
      MyApp app = (MyApp)appIterator.next();
      PastryNode node = (PastryNode)app.getNode();
Other than that, we changed the delay in several locations so the program doesn't take as long to execute. Compile and run this program as before, but make sure to specify some the number of nodes to run as the 4th argument.
java -cp .:FreePastry-@freepastry_version@.jar rice.tutorial.lesson4.DistTutorial 9001 10.9.8.7 9001 10
:1122933905343:Error connecting to address /10.9.8.7:9001: java.net.ConnectException: Connection refused: no further information
:1122933905359:No bootstrap node provided, starting a new ring...
Finished creating new node SocketNodeHandle (<0x93426F..>/FOO/10.9.8.7:9001 [6666451457797044406])
Finished creating new node SocketNodeHandle (<0xAE1B63..>/FOO/10.9.8.7:9002 [8904287830673843378])
Finished creating new node SocketNodeHandle (<0x3E99E3..>/FOO/10.9.8.7:9003 [-1171813548315184530])
Finished creating new node SocketNodeHandle (<0xC8715F..>/FOO/10.9.8.7:9004 [6496343980737954414])
Finished creating new node SocketNodeHandle (<0x688826..>/FOO/10.9.8.7:9005 [-6779179910423314388])
Finished creating new node SocketNodeHandle (<0x640179..>/FOO/10.9.8.7:9006 [3471226224877450778])
Finished creating new node SocketNodeHandle (<0x7A6F99..>/FOO/10.9.8.7:9007 [7101267768505206817])
Finished creating new node SocketNodeHandle (<0xD5DAAE..>/FOO/10.9.8.7:9008 [7899110252170216207])
Finished creating new node SocketNodeHandle (<0x19C832..>/FOO/10.9.8.7:9009 [-4206970387543598705])
Finished creating new node SocketNodeHandle (<0x490C38..>/FOO/10.9.8.7:9010 [-6742572645641651296])
MyApp <0x93426F..> sending to <0x0E510A..>
MyApp <0x19C832..> received MyMsg from <0x93426F..> to <0x0E510A..>
MyApp <0xAE1B63..> sending to <0xE704A5..>
MyApp <0xD5DAAE..> received MyMsg from <0xAE1B63..> to <0xE704A5..>
MyApp <0x3E99E3..> sending to <0x533803..>
MyApp <0x490C38..> received MyMsg from <0x3E99E3..> to <0x533803..>
MyApp <0xC8715F..> sending to <0x779E75..>
MyApp <0x7A6F99..> received MyMsg from <0xC8715F..> to <0x779E75..>
MyApp <0x688826..> sending to <0x3FFFB9..>
MyApp <0x3E99E3..> received MyMsg from <0x688826..> to <0x3FFFB9..>

...

MyApp <0x93426F..> sending direct to [SNH: <0x93426F..> -> <0xAE1B63..>/FOO/10.9.8.7:9002 [8904287830673843378]]
MyApp <0xAE1B63..> received MyMsg from <0x93426F..> to <0xAE1B63..>
MyApp <0x93426F..> sending direct to [SNH: <0x93426F..> -> <0xC8715F..>/FOO/10.9.8.7:9004 [6496343980737954414]]
MyApp <0xC8715F..> received MyMsg from <0x93426F..> to <0xC8715F..>
MyApp <0x93426F..> sending direct to [SNH: <0x93426F..> -> <0xD5DAAE..>/FOO/10.9.8.7:9008 [7899110252170216207]]
MyApp <0xD5DAAE..> received MyMsg from <0x93426F..> to <0xD5DAAE..>
MyApp <0x93426F..> sending direct to [SNH: <0x93426F..> -> <0x19C832..>/FOO/10.9.8.7:9009 [-4206970387543598705]]
MyApp <0x19C832..> received MyMsg from <0x93426F..> to <0x19C832..>
MyApp <0x93426F..> sending direct to [SNH: <0x93426F..> -> <0x3E99E3..>/FOO/10.9.8.7:9003 [-1171813548315184530]]
MyApp <0x3E99E3..> received MyMsg from <0x93426F..> to <0x3E99E3..>
MyApp <0x93426F..> sending direct to [SNH: <0x93426F..> -> <0x490C38..>/FOO/10.9.8.7:9010 [-6742572645641651296]]
MyApp <0x490C38..> received MyMsg from <0x93426F..> to <0x490C38..>

...

Congratulations! You have just created an entire ring inside a single JVM. This should make it much easier to test your application.