org.jboss.remoting.transport.multiplex
Class MultiplexingManager.ShutdownManager

java.lang.Object
  extended by org.jboss.remoting.transport.multiplex.MultiplexingManager.ShutdownManager
Enclosing class:
MultiplexingManager

protected class MultiplexingManager.ShutdownManager
extends java.lang.Object

The motivation behind this class is to prevent the following problem. Suppose MultiplexingManager A is connected to MultiplexingManager B, and A decides to shut down. Suppose A shuts down before B knows A is shutting down, and suppose a VirtualSocket C starts up, finds B, and attaches itself to B. Then C will have "died a-borning," in the words of Tom Paxton. We need a handshake protocol to ensure a proper shutdown process. In the following, let A be the local MultiplexingManager and let B be its remote peer. There are two forms of synchronization in ShutdownManager. incrementReferences() and decrementReferences() maintain the reference count to its MultiplexingManager, and of course the changes to variable referenceCount have to be synchronized. Parallel to incrementReferences() and decrementReferences() are the pair of methods reseverManager() and unreserveManager(), which are similar but intended for holding a MultiplexingManger for more temporary applications. See, for example, getaManagerByRemoteAddress(). There is also a need for distributed synchronization. When decrementReferences() on A decrements the referenceCount to 0, it indicates to B the desire of A to shut down. Since all of the virtual sockets on A are connected to virtual sockets on B, normally the request would be honored. However, if a new virtual socket attaches itself to B, then it would have > 0 clients, and it would refuse the request to shut down. In any case, the request is made through Protocol.requestManagerShutdown(), which results in a call to ShutdownManager.respondToShutdownRequest() on B, which is synchronized since it reads the readyToShutdown variable, which is modified by decrementReferences(). Here lies the danger of distributed deadlock. If decrementReferences() on A and B both start executing at about the same time, they would both be waiting for a response from respondToShutdownRequest(). But each respondToShutdownRequest() would be locked out because each decrementReferences() is blocked on i/o. The solution is to put the i/o operation in a separate thread, ShutdownRequestThread, and have decrementReferences() enter a wait state, allowing respondToShutdownRequest() to execute. So, on each end respondToShutdownRequest() will return an answer ("go ahead and shut down", in particular), and each ShutdownRequestThread.run() will wake up the waiting decrementReferences(), which will then run to completion. Note also that while decrementReferences() is waiting, incrementReferences() can run. However, before it waits, decrementReferences() sets the shutdownRequestInProgress flag, and if incrementReferences() finds the flag set, it will also enter a wait state and will take no action until the outstanding shutdown request is accepted or rejected. Another issue is what to do if MultiplexingManager B responds negatively to A's request to shut down, not because it has a new client but simply because some of its virtual sockets just haven't gotten around to closing yet. When B's referenceCount finally goes to 0, it will send a shutdown request to A, and if A's referenceCount is still 0, B will shut down. But what about B? If decrementReferences() gets a negative response, it will start up a ShutdownMonitorThread, which, as long as readyToShutdown remains true, will periodically check to see if remoteShutdown has been set to true. If it has, ShutdownMonitorThread initiates the shut down of its enclosing MultiplexingManager. reserveManager() interacts with decrementReferences() by preventing decrementReferences() from committing to shutting down. If reserveManager() runs first, it sets the flag reserved to true, which causes decrementReferences() to return without checking for referenceCount == 0. If decrementReferences() runs first and finds referenceCount == 0 and gets a positve response from the remote manager, then reserveManager() will throw an IOException. But if decrementReferences() gets a negative response, it will start up a ShutdownMonitorThread, which runs as long as the flag readyToShutdown is true. But reserveManager() will set readyToShutdown to false, ending the ShutdownMonitorThread. When unreserveManager() eventually runs and sees referenceCount == 0, it will increment referenceCount and call decrementReferences(), allowing the shutdown attempt to proceed anew. Note that when incrementReferences() runs successfully, it sets the flag reserved to false, since incrementing referenceCount will also keep the MultiplexingManager alive.


Constructor Summary
protected MultiplexingManager.ShutdownManager()
           
 
Method Summary
 void decrementReferences()
           
 void incrementReferences()
           
protected  boolean isShutdown()
           
 void reserveManager()
           
protected  boolean respondToShutdownRequest()
           
 void unreserveManager()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

MultiplexingManager.ShutdownManager

protected MultiplexingManager.ShutdownManager()
Method Detail

reserveManager

public void reserveManager()
                    throws java.io.IOException
Throws:
java.io.IOException

unreserveManager

public void unreserveManager()

incrementReferences

public void incrementReferences()
                         throws java.io.IOException
Throws:
java.io.IOException

decrementReferences

public void decrementReferences()

respondToShutdownRequest

protected boolean respondToShutdownRequest()
Returns:

isShutdown

protected boolean isShutdown()
Returns:


Copyright © 1998-2005 JBoss Inc . All Rights Reserved.