Shahzad Bhatti Welcome to my ramblings and rants!

November 22, 2008

Implementing Actor-based message passing using Object-oriented methods

Filed under: Computing — admin @ 11:01 am

I wrote about use of actor based programming for parallel and concurrent programming previously [ 1 , 2 ], where an actor keeps its own thread of execution with a mailbox. Actors communicates to other actors by sending messages that are delivered to its mailbox. In this model, the message passing takes literal form rather than method invocation. I studied Actor based parallel computing in my post graduate research on parallel and distributed field. I learned message passing systems such as Actors, MPI, MPL were much more scalable than shared memory. This describes popularity of languages like Erlang and Scala that has adopted Actor model to tackle concurrency (object-oriented nature in Erlang). According to Ralph Johnson concurrent Erlang is object oriented. Alan Kay has also argued that message passing is more important than objects in object-oriented programming and regrets that he chose the term “object-oriented” instead of “message-passing”. Even Joe Armstrong, who generally dislikes object oriented programming admits similarity between object-oriented programming and Erlang’s message passing.

However, despite effectiveness of message passing in new era of concurrency, I find that pure message passing is a bit intimidating to an average programmer. In this blog, I will show how an object-oriented methods can be used to abstract actor-based message passing. The primary benefit of message passing alongside with immutability is its support of concurrency so the following example will demonstrate use of message passing in multiple threads. Let’s suppose, we are designing a simple chat service to send and receive messages and the message looks like following:

Java

Following is an interface for the chat service:

Java

Note that above interface uses “@Asynchronous” annotation for “sendMessage” and “clear” methods. One of the benefit of message-passing is that you can optionally send asynchronous messages. So I defined an annotation to declare a particular method as asynchronous, e.g.

Java
Following code implements the chat service in non-thread-safe fashion:
Java

Note that above code cannot be used in multi-threading environment. If we were building thread-safe service using Java, we would have to add synchronization or locking such as:

Java
Above code demonstrates use of composition to convert a non-thread-safe class into a thread-safe class.

Now the meat of this library is following factory class that converts any Java object into an actor:

Java
The ActoryFactory uses reflection and proxy features of Java. The client code creates an actor by invoking
Java
      
The create method instantiates a blocking queue that serves as mailbox for the actor and then starts a thread. The create method then instantiates InvocationHandler that intercepts all methods. Finally, the proxy object is returned to the client. When the client invokes any method it is intercepted by the proxy, which then sends the message to the mailbox of the actor. The proxy also checks if the method i defined as asynchronous then it does not wait for the reply. The thread simply waits until there is a message in the mailbox. The message for the actor is defined in MethodRequest that encapsulates reflection information to invoke a method. The actor thread invokes the method using reflection and puts back reply in the queue supplied by the proxy. The proxy waits for the reply and then sends back the reply back to the client. As an actor serves one request at a time, there is no need for locking or synchronization.

Following code demonstrate client test code:

Java
Above class demonstrates a variety of way you can instantiate service class, e.g. by simply invoking the constructor, using reflection and using actors. Note that you cannot simply run non-thread-safe implementation because it would produce incorrect results. For each type of service, the test creates 100 threads that try to send and receive messages. By the end of each test, 200,000 messages are sent and retrieved. Following are runtimes for the service invocation:
 Completed thread-safe direct in 286 millis
 Completed Actor model in 1412 millis
 Completed thread-safe reflection in 693 millis

As expected, using builtin synchronization yields the fastest response, reflection adds some overhead and finally actor based communication adds considerable more overhead. One of the feature of Erlang is its support of seamless networking support. Using an abstraction layer as above can easily be enhanced to start an actor on remote machine. Though, in that case the service will only exist on the remote server. As threads in Java are natives and map to light-weight process, they are much more heavy weight than process in Erlang, which only consumes 300 bytes per process. I have found that native threads are more suitable for CPU-bound processing and green or user-based threads suit well for IO-bound processing. In the end, biggest gain of above design from programmer’s perspective is that the client code looks exactly like any other object oriented and unlike Erlang you get real type safety in message passing. Another big advantage is use of polymorphism, above technique uses dependency inversion principle to interface and implementation separate, thus actual implementation can be changed as needed.

You can download all code from here

November 5, 2008

Ten things I hate about Enhydra Shark

Filed under: Computing — admin @ 12:17 pm

I am trying to use Enhydra Shark at work for implementing a workflow system, but I have been finding a lot of issues with it. Here are ten things that I found absolutely aweful about the Enhydra Shark:

  1. All methods throw Exception as part of the signature instead of specific exceptions.
  2. It uses constants instead of enums.
  3. Many classes use public fields and underscore as part of the name, e.g.
                      public final class AppParameter {
                                     public String the_actual_name = null;
     

    it reminds me of a quote ‘You can write FORTRAN in any language”.

  4. Every single Shark method requires transactions and many of the methods open and close several transactions per method, e.g. real code from another group using Shark:
                userTxn = getUserTransaction();
                userTxn.setTransactionTimeout(600);
                userTxn.begin();
                                                                                                  
                 // Connect to the shark process repository
                 SharkConnection connection = shark.getSharkConnection();
                 connection.attachToHandle(executor.getSharkSessionHandle());
     
                 WfProcess process = loadProcess(connection, userTxn);
                 userTxn.commit();
     
                 userTxn.begin();
                 WfActivity activity = loadActivity(shark, userTxn, connection);
                 userTxn.commit();
                                                                                                  
                 userTxn.setTransactionTimeout(600);
                 userTxn.begin();
                 WMSessionHandle toolAgentSession = toolAgent.connect(connectionInfo);
                 toolAgent.invokeApplication(session, toolAgentSession.getId(),
                             appInfo, toolInfo, null, processInstanceId, assignmentId,
                             parameters, appMode);
                 connection.disconnect();
                 userTxn.commit();
     

    Worst, some of the methods require both local and XA transactions.

  5. It uses its own connection factory so I can’t use apache commons or other connection pool. It defines connection properties in several files, which don’t work as expected, e.g. some parameters are used for upper bound and other for lower bound.
  6. It uses its own transaction factory so I can’t use declarative transactions using annotations or Spring. It is just not designed to work with any other framework.
  7. It requires each JVM to connect with a unique engine name and another team had to generate that name on startup.
  8. Its community does not answer questions (I never got response of my questions) and last activity on the mailing list was 10 months old.
  9. It does not use latest XPDL 2.0, which has been released a few years ago.
  10. Due to explicit connection management and transaction management several times per method, other groups using Shark found a lot of problems with multi-threading, scalability and reliability.

I like the frameworks or languages that follow “principle of least surprise”, on the other hand Shark follows “principle of voodoo magic” to get things working. In the end, I have not completely given up on Shark engine, but I have very low expectations.

Powered by WordPress