Synchronization in JavaSymphony

    Lock/Unlock mechanism for JSObject already provides a way to synchronize concurrent access to methods of a remote object. JavaSymphony provides two additional synchronization mechanism, which we consider useful for parallel application:
  1. Synchronization of asynchronous method invocations allows the synchronization at the end of the execution of several methods running asynchronously in parallel;
  2. Barrier synchronization allows synchronization while methods are executed in parallel.

Synchronization of Asynchronous Method Invocations

     JavaSymphony enables a programmer to group a set of result handles -- each one associated with a unique asynchronous remote method invocation -- by using a class ResultHandleSet. This class provides several methods to block or examine (without blocking) whether one, a certain number, or all threads finished processing their methods. Frequently, methods of different objects -- that reside on different computing nodes -- are executed in parallel, in order to implement load balancing. By using a synchronization mechanism we can easily determine which object is idle because the execution of its method has finished. The following excerpt of code illustrates these features:
JSObject obj[n];
ResultHandleSet rhs;
ResultHandle rh;
Object[] params;
...

for(i=0; i < n; i++)
{
      // add a ResultHandle and index i (optional) to the ResultHandleSet rhs
    rhs.add(obj[i].ainvoke("run", params), i);
}
...

   //non-blocking test if at least 5 methods are finished
if( rhs.isReady(5) ) {...}
   //non-blocking test if all methods are finished
if( rhs.isAllReady() ) {...}
   //block until at least 5 methods are finished
if( rhs.waitReady(5) ) {...}
   // block until all methods are finished
if( rhs.waitAll () ) {...}

   // get results one by one without specific order; block until the first method has returned results
rh = rhs.getFirstReady();
while(rh != null) {
         // get the results
    ResultClass result = (ResultClass)rh.getResult();
     ... // process results
        // get index of idle object
    index = rhs.getIndex(rh);
        // invoke next method on idle object for load balancing and add ResultHandle in ResultHandleSet again
    rhs.add( obj[index].ainvoke("run", params), index);
       // get ResultHandle of a method that finishes next; block until results returned
    rh = rhs.getNextReady();
}

Barrier Synchronization

    JavaSymphony provides a barrier for methods called in JS objects. The flow of control for a set of threads can be suspended until all of these threads reach a certain barrier point.
A number of barriers can be defined for each JS application by using a static method newBarrier -- part of JSRegistry class -- with an identifier that uniquely identifies the barrier, and the number of the threads n which have to wait at this barrier. The barrier is visible by all objects of the application. The execution of the threads reaching a barrier point is suspended until exactly n threads reach this point. Thereafter, all threads can resume execution beyond the barrier.
The following code excerpt demonstrates the usage of the JS barrier operation:

    // a barrierId defines a unique synchronization point
int barrierId = 17;
    // define a barrier for two (remote) threads.
JSRegistry.newBarrier(2, barrierId);
obj1.oinvoke("runThread1", params);
obj2.oinvoke("runThread2", params);
 ...

    // inside runThread1
int barrierId = 17;
    // suspend execution until runThread2 reaches the synchronization point
JSRegistry.barrier(barrierId);
...

    // inside runThread2
int barrierId = 17;
    // suspend execution until runThread1 reaches the synchronization point
JSRegistry.barrier(barrierId);
...

Events in JavaSymphony

   JS follows a general event model where objects can subscribe as consumers for various types of events. Events with a specific type can be produced and the registered consumers will be notified. An event consumer handles the event by providing an appropriate method.
    A specific advantage of the event mechanism is that JS does not restrict the types of objects which receive or produce events. Any Java object distributed by using JavaSymphony can consume or produce events without implementing dedicated interfaces or extending dedicated JS classes.
    JavaSymphony supports three types of events:
  1. User Defined Events are generated explicitly by the user. They are used to support asynchronous communication and interaction among arbitrary Java objects (not restricted to JS objects). The programmer must provide the code for the producer, which generates an event and a method which is invoked by the consumer when the notification for the event arrives. 
  2. Middleware Events are produced and controlled by the JRS in the event of, for instance, VA unavailable, (un)registration of a new application,  object (un)lock or VA (un)lock, etc. The user must provide only the method that is invoked when notification for the event arrives, whereas the JRS produces these events.
  3. System Events are invoked due to changes of dynamic system parameters such as idle time, available memory, swap space allocated, etc. All of these parameters can be accessed by the programmer through the JS API for static/dynamic system parameters . For the consumer object a set of constraints, a constant that controls the generation of an event, and a method which is invoked if the event occurs, are specified as constructor parameters. The constant determines the event generation if the set of constraints holds, does not hold, or changes.
    An object that wants to consume a user-defined or JS-middleware event creates a JSEventConsumer which describes the type (middleware or user-defined) and properties of the event in which it is interested. A derived class JSSystemEventConsumer is used for system events. When building an instance of JSEventConsumer,
the programmer provides the following information:
    Events can be filtered by specific parameters passed to the constructor. A set of constants for event types is defined as part of the JSConstants class. For example:
    Similarly to filter the events:
    For JSSystemEventConsumer a JSConstraints object encapsulate the constraints which will be checked in order to produce a system event. An additional parameter controls the generation of the event, if the constraints become valid (JS_CONSTRAINTS_HOLD), invalid (JS_CONSTRAINTS_ NOT_HOLD), or their status changes (JS_CONSTRAINTS_CHANGE). For every different set of constraints, a distinct system event will be generated by the JRS which causes all consumers to be notified accordingly.
    The consumer subscribes an event by using the subscribe method of the JSConsumerEvent class.If specific events should no longer be received, then the consumer
will use the unsubscribe method. Only user-defined events can be explicitly produced by the programmer through the JSEventProducer object. The first constructor parameter indicates the object that generates an event. The second parameter refers to the unique type of the generated event which must match with the second parameter of JSEventConsumer. Moreover, the same list of constants defined in JSConstants is used to restrict the list of consumers.
    The following code excerpt demonstrates the usage of the JS events:
...

// ****** Code for Event Consumer ********
...
    // define types for user defined and middleware events
int userEvType = JSConstants.C_USER_TYPE + 1;
int middleEvType = JSConstants.C_APP_REGISTERED;
JSObject listObj[]=.....; // list of remotes objects
VA listVAs[]=.....; // list of VAs
JSConstraints constr1;

    // subscribe for a user defined event; no restriction on  event producers; handleMethod will handle events.
JSEventConsumer cEv1 = new JSEventConsumer(this, userEvType, JSConstants.C_ANY_LOCATION, "handleMethod");
    // events can be produced only on VAs in listVAs
JSEventConsumer cEv2 = new JSEventConsumer(this, userEvType, JSConstants.C_LIST_VA_EVENT, listVAs, "handleMethod");
    // event can be produced only by JSObjects in listObj
JSEventConsumer cEv3 = new JSEventConsumer(this, userEvType, JSConstants.C_LIST_JSOBJECT_EVENT, listObj, "handleMethod");

    // subscribe for a middleware event which can be produced anywhere;the event is generated when a new application registers with JS
JSEventConsumer cEv4 = new JSEventConsumer(this, middleEvType,JSConstants.C_ANY_LOCATION, "handleMethod");

\> // subscribe for a system event which can be produced only by the VA va when the validity for a set of constraints constr changes
JSSystemEventConsumer cEvSystem =  new JSSystemEventConsumer(this, JSConstants.C_VA_EVENT, va, "handleMethod", constr, JSConstants.JS_CONSTRAINTS_CHANGE);
...
    // subscribe for event cEv1
cEv1.subscribe();
...
    // unsubscribe for event cEv1
cEv1.unsubscribe();
...

// ****** Code for Producer of User-Defined Events ******** 
...
int userEvType = JSConstants.C_USER_TYPE + 1;
Object listObj[]=.....; // list of remotes objects
Object listVAs[]=.....; // list of VAs

    // produces a user-defined event of type userEvType; no restriction on event consumers
JSEventProducer pEv1 = new JSEventProducer (this, userEvType, JSConstants.C_ANY_LOCATION);
    // notify only those consumers registered on VAs in listVAs
JSEventProducer pEv2 = new JSEventProducer (this, userEvType, JSConstants.C_LIST_VA_EVENT, listVAs);
    // notify only those consumers in listObj
JSEventProducer pEv3 = new JSEventProducer (this, userEvType, JSConstants.C_LIST_JSOBJECT_EVENT, listObj);
...
    // produce a user-defined event; parameters will be transmitted to the handleMethod of matching consumer
Object params[]=.....;
pEv1.produceEvent(params)
...

Locality Control

The Locality Control Module (LCM) is a part of the JSR that applies and manages locality constraints on the executing JS application by mapping JS objects and tasks onto the VA nodes. In JS, We can specify locality constraints at three levels of abstraction:

  1. Application-level locality constraints are applied to all JS or SJS objects and all future data allocations of a JS application. The locality constraints can be specifed with the help of setAppAffinity static method of the JSRegistry class.
  2. Object-level locality constraints are applied to all method invocations and data allocations performed by a JS or SJS object. The object-level locality constraints override any previous application-level constraints for that object.
  3. Task-level locality constraints are applied to specific task invocations and override any previous object or application-level constraints for that task.

The LCM in coordination with the OAS job processing mechanism applies the locality constraints. The jobs are processed by the job handler threads within an OA. The job handlers are JVM threads that are executed by some system-level threads such as the POSIX threads on a Linux system. Below we show some code example related to locality specification at three levels.
......
// Creating a level-0 VA which represents a core
VA c1 = new VA(new int[]{0},0);

// Creating a level-1 VA which represents a processors
VA p1 = new VA(new int[]{0},1);

//Creating a level-2 VA  ( a machine or workstation)
VA v1 = new VA(2);

//Add core to processor, processor to machine
p1.addVA(c1);
v1.addVA(p1);
.......
//Application level locality
JSRegistry reg=new JSRegistry("MyApp",v1);
.........
//Object level locality
SJSObject obj1 = new SJSObject(false,"MyClass",new int[]{},p1);
.........
//
Task level locality
ResultHandle handle = obj1.ainvoke("MyMethod", new int[]{methodID},c1};