Blitz Project Pattern Library

Back to Blitz Project

Introduction

Here you will find a (hopefully growing) collection of patterns and blueprints for deployment and software architecture of systems based on JINI and JavaSpaces.

Jini Blueprints

Coming soon: Advice on constructing simple resilient implementations

Update: 23/2/2004 Completed testing over the weekend. It works! I've submitted a presentation proposal for the Seventh JINI community meeting. Full implementation blueprint to follow soon.

Update: 17/6/2004 Presentation slides are here.

JavaSpaces Patterns

Considerations in Designing for JavaSpaces

As mentioned in the overview, it is best to design solutions based on JavaSpaces around the concept of object flows rather than attempting to, for example, create the equivalent of a database schema containing objects each of which has a unique key to allow direct addressing. This section provides some notes on problems often encountered when implementing JavaSpace-based solutions.

Concurrency

Consider, for a moment, the scalability of a simple algorithm running in a single JVM consisting of multiple threads writing to and reading from a single-lock queue:
  1. For a small number of threads there will be no perceived bottleneck.
  2. For a large number of threads running on an 8-way SMP box, this single lock queue becomes a hotspot of contention owing to the fact that all threads will "fight" for the single-lock.
Now let's think about creating an equivalent queue for use with a JavaSpace.
  1. We now have a distributed environment in which we may have considerably more than 8 processors accessing the JavaSpace and contending for that lock.
  2. The remote nature of JavaSpaces introduces additional issues of latency etc.
Clearly the problem of contention will be exaggerated by the use of a JavaSpace. Consequently, many of the common concurrent structures used in single JVM situations need modification for use in the JavaSpaces environment. Possible approaches include:
  1. Partitioning of data into a number of separate structures - in the case of our example, multiple queues.
  2. Partitioning of data across multiple spaces. Often paired with the partitioning of available machines into groups each of which is responsible for processing entries from one space.
  3. Adoption of scatter/gather type algorithms.
  4. Use of more complex concurrent structures.

Tree-based algorithms can also suffer contention issues owing to the potential for conflict over the root node and the first few layers of children. Again, the normal solutions apply such as, high-fanout at the root node, splitting into separate trees, node caching etc.

Unique Identifiers

In a number of usage patterns, it is desirable to arrange for each Entry to have some form of unique identifier. This presents a number of challenges in terms of state maintenance including the need for clients to "remember" which id's have been allocated.

This problem can be simplified as follows:

  1. Do not re-use id's - ensure the range of available id's is sufficiently high as to avoid exhaustion.
  2. Have a component of the id be based on a client-unique value such as IP address (of course, IP address isn't always sufficient but you get the drift).
  3. Have a further component of the id be based on the time of client startup - this allows us to avoid issues around client-state recovery after a crash.
So a typical id might look something like:
public class Id implements java.io.Serializable {
// Starts from zero, incremented by one for each new id
private long theSequenceNumber;

// Based on System.currentTimeMillis()
private long aTimestamp;

// Derived from InetAddress's byte[] representation.
private byte[] theIPAddress
}

You might also wish to look at the JINI 2.0 classes net.jini.id.UuidFactory and net.jini.id.Uuid.

Use of Notify

There are two important aspects of notify to be considered in all designs making use of JavaSpaces:

  1. Timely delivery of events cannot be assumed - that is, the event associated with a particular write may be delivered any time after the write completed.
  2. Event delivery cannot be guarenteed - a JavaSpaces implementation will typically make "best endeavours" to deliver event's to registered clients.

Thus notify cannot be considered to be reliable.....

A good approach to the use of notify is to have client's register for events and use that as the primary source of information for the client. Backing this up, you should occasionally use a take/read to query the JavaSpace for appropriate information. The take/read not only allows the programmer to recover from missing events but also to detect network/server issues which may be preventing event delivery, facilitating construction of suitable recovery mechanisms.

Another option is to have each client register for notify and then delegate event collection to an event mailbox situated close (in network terms) to the JavaSpaces server. The client can then rely solely on gathering events from the mailbox rather than having to use additional threads for background takes/reads. This is simpler but "more brittle" than the first solution. Locating the mailbox "close" to the server also reduces the likelihood of event loss due to fewer network hops and can also improve network utilization.

Separation of Concerns

Many JavaSpaces examples and deployed JavaSpaces systems mix code for access to a JavaSpaces instance with code that performs other tasks in the same class. For small applications this is probably acceptable but more substantial systems should aim to separate the JavaSpaces code into a collection of library classes.

This makes code maintenance more easy by making it simpler to change the Entry "protocol" without disturbing anything else. It may also be useful future proofing because JavaSpaces may gain some form of code uploading feature for the purposes of accelerating performance and allowing implementation of a wider variety of systems.

See here and here for more discussion on code uploading in respect of JavaSpaces.

State Initialization

A common problem in many potential JavaSpaces applications is ensuring that only one instance of a particular Entry exists within a particular JavaSpace. This is seen in many scenarios including some forms of searching and multi-player games.

As yet, nobody has come up with a solution for this problem based solely on the use of the JavaSpaces API. However, the Blitz Project has implemented a distributed lock manager which provides a fault-tolerant locking service.

Basic usage would be something like:

  1. Check for presence of unique Entry
  2. Start transaction T
  3. If no Entry found, obtain a lock from the distributed lock manager using T
  4. Check for presence of unique Entry
  5. If Entry not present, create it and write it using T
  6. Commit T

This process ensures that only one entity will successfully create the unique Entry. Note care must be taken in deducing that an Entry does not exist. It may, for example, be necessary to have anyone manipulating the Entry, perform the operation under a lock or use some form of timeout such that if the Entry is not visible within a certain amount of time, it can be assumed it needs to be re-created.

The Blitz Lock Manager can be found here

Back to Blitz Project

Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the U. S. and other countries