Global Logical Clock

Overview

With the 1.3.0 release of the MASS library, a new feature has been introduced to make it easier to develop applications that simulate the passing of time or synchronization of events based upon the notion of a global clock, the value of which being consistent among all cluster nodes.

How it Works

The Global Logical Clock is a long datatype value that increments with each call to Agents.manageAll, .doAll, .doWhile, and .doUntil. When the clock value increments, all cluster nodes will receive this new value automatically.

Agents may contain methods that are invoked upon the clock reaching:

In addition to triggering events (method invocation) upon the clock value reaching some value, applications may query and even control the clock in a limited manner:

For each clock iteration, every node will compute the next value at which an event is scheduled to occur and will automatically “fast forward” the clock to skip over values that would not trigger an event. This prevents the clock from incrementing through cycles that would not trigger a change in the simulation.

Agent Clock Annotations

Annotations are used to determine which methods are invoked when the clock reaches specified values. Although there is only one annotation (“@Clocked”) used to describe the Agent methods to be invoked by the clock, there are three different ways to specify when the method is to be invoked:

On Every Clock Cycle

If you would like to have an Agent method invoked on each iteration of the clock value (on every “tick”), simply decorate the method with the “@Clocked” annotation with no arguments as follows:

#!java

    @Clocked
    public void onEveryClockCycle( ) {
    
        // simulate movement down the path
        myDistanceTravelled += pathLength;

    }

On Values Of

You may want to have a method invoked on specific values of the clock and not any other time. Here are some examples of annotating methods to occur at specific “times”:

#!java

    @Clocked( onValuesOf = { 2 } )
    public void doDelayedInitialization( ) {
    
        // perform second series of initialization functions, now that the first set has completed
        doSecondStageInit();

    }

    @Clocked( onValuesOf = { 5, 10, 15, 20 } )
    public void checkForCollision( ) {
    
        // only at clock cycles 5, 10, 15, and 20 should we check for collision
        doCollisionCheck();

    }

On Multiples Of

The final type of clocked method invocation is on multiples of the clock value. Here is an example of a method that would be called every fifth clock cycle:

#!java

    @Clocked( onMultiplesOf = { 5 } )
    public void onEveryFifthClockCycle( ) {
    
        // is this Agent being followed?
        if ( isFollowed() ) {
            doHide();
        }

    }

Just like “onValuesOf”, you can specify several multiples for invocation:

#!java

    @Clocked( onMultiplesOf = { 2, 3, 5, 7, 11 } )
    public void onFirstPrimes( ) {
    
        // check for local minima
        if ( currentValue < minValue ) {
            minValue = currentValue;
        }

    }

Controlling the Global Logical Clock

As described previously, the clock will increment after each call to Agents.manageAll, .doAll, .doWhile, and .doUntil. It is possible, though, to control the clock from your main application. There are a few methods that you may use to control the clock during the simulation:

getValue()

Not a controlling method, but you can obtain the current clock value using this method.

increment()

Calling this will cause the Global Logical Clock to increment by one.

reset()

Use this method to reset the clock to a value of zero.

setValue( long newValue )

You can force the clock to a specified value using this method. After each node is set to this new value, all Agents will be evaluated to see if @Clocked method invocations are in order.