|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.jboss.remoting.transport.multiplex.MultiplexingManager.ShutdownManager
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, then 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 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()
FIXME Comment this |
void |
incrementReferences()
|
protected boolean |
isShutdown()
FIXME Comment this |
void |
reserveManager()
FIXME Comment this |
protected boolean |
respondToShutdownRequest()
FIXME Comment this |
void |
unreserveManager()
FIXME Comment this |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
protected MultiplexingManager.ShutdownManager()
Method Detail |
public void reserveManager() throws java.io.IOException
java.io.IOException
public void unreserveManager()
public void incrementReferences() throws java.io.IOException
java.io.IOException
public void decrementReferences()
protected boolean respondToShutdownRequest()
protected boolean isShutdown()
|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |