3. Runtime System

3.1 Goals

The runtime system has to provide a uniform view of the underlying network to all agents. It hides the distribution aspects as much as possible and tries to hide problems in the underlying system like broken links and node crashes. It provides simple messaging and agent management primitives to the agents in the next-higher layer.

3.2 Overview

The mobile agent system consists of a set of agent storages which again manage a set of agents. These again can migrate from storage to storage and communicate with other agents. As can be seen in the following figure, an agent storage can be mapped onto one or multiple physical nodes.

At the same time, multiple agent storages can be mapped onto the same node. In other words, agent storages represent virtual nodes rather than physical nodes. The advantage of this approach is that the introduction of fault-tolerance is simplified: if each virtual node is mapped onto n physical nodes, up to n-1 node failures can be tolerated.

In the next subsections, we will discuss two functions of the MAM in more detail.
 

3.3 Agent Management Subsystem

The agent management subsystem is responsible for agent creation, destruction, and migration. Each agent in the MAM system has a globally unique ID, called agent ID. It is stored in the class AgentID. In order to refer to agent storages, each of them also gets a globally unique ID, called storage ID. It is stored in the class StorageID.
In order to keep track of agents that currently recide on a node, agent storages maintain three tables: These are located in the class AgentStorage as instance variables named whitePages, threadPages, and grayPages, respectively. All three tables are hashtables mapping an agent ID to a GenericAgent object, a thread, or a storage ID, respectively.

Whenever an agent is created, a new agent ID and GenericAgent object (of the correct subtype) is created and stored in the whitepages. All new agents are inactive at the beginning, i.e. no new thread is created. If an agent is activated, a new thread is created and stored in the thread pages. The new thread starts its execution in the live method of the agent object.

To migrate an agent to some other node n, the following steps are necessary:

  1. wait for all agent threads to terminate,
  2. serialize and send the Java agent object to node n,
  3. deserialize it there and start a new thread,
  4. update the forwarding table.
The last step includes storing a mapping from the agent ID to its new location (a storage ID) in the forwarding table. If a message arrives for the agent that migrated, the storage can forward it to the new location of the agent, hoping the agent is still there. Otherwise, the message is forwarded further until the agent is reached or detected as no longer existent.

The methods to create, destroy, and migrate agents are:

3.4 Messaging Subsystem

The messaging subsystem provides functionality to send messages to other agents and to deliver incoming messages.

To send a message m to some agent with id i, the following steps are taken:

  1. if the message is for a local agent, create a new thread to handle it,
  2. elsif the message is for an agent that was here, but migrated to a node n, forward it to node n,
  3. elsif the message is for an unknown agent, forward it to the storage where the agent was created (can be obtained from the agent ID).
Obviously, the agent storage has to maintain a table of forwarding pointers for each agent that ever visited the node. The garbage collection of no longer needed pointers is part of the future work.

The messaging subsystem supports three types of message sending:

Whenever a message with future result is sent, the storage stores a future variable in a table called futurePages. As soon as the result is sent back to the storage, the result is entered in the future variable and thereby the agent waiting for the result is unblocked.
Synchronous sends can be simulated with asynchronous send with future result by waiting for the result immediately after sending the message.
The multicast send sends a message to all agents of a certain type. More details about the multicast send can be found here.

In order to support "anonymous communication", the storage provides a whiteboard mechanism which is implemented as a tuple space. Agents can search for tuples (anonymous receive), or insert tuples by themselves (anonymous send). Since multiple agents may perform an anonymous receive or one agent may perform an anonymous receive for multiple sends, this mechanism also allows multicasts (i.e. 1-to-many sends) and the opposite (i.e. many-to-1 sends).

The methods for message sending and tuple space usage are: