New very safe shutdown scheme. An Invoker.Unit runs on both the Invoker
and dobj thread until they're both empty (or it has been passed 50 times) and then shuts the threads down. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2744 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: PresentsDObjectMgr.java,v 1.34 2003/06/15 16:47:33 mdb Exp $
|
||||
// $Id: PresentsDObjectMgr.java,v 1.35 2003/08/08 03:11:55 ray Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
@@ -254,12 +254,6 @@ public class PresentsDObjectMgr
|
||||
*/
|
||||
protected void processEvent (DEvent event)
|
||||
{
|
||||
// handle graceful shutdown
|
||||
if (event instanceof ShutdownEvent) {
|
||||
_running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// look up the target object
|
||||
DObject target = (DObject)_objects.get(event.getTargetOid());
|
||||
if (target == null) {
|
||||
@@ -325,14 +319,17 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the dobjmgr shut itself down. It will exit the event
|
||||
* processing loop which cause <code>run()</code> to return.
|
||||
* Requests that the dobjmgr shut itself down soon- you may
|
||||
* want to try using {@link Invoker#shutdown} which will make sure that
|
||||
* both the Invoker and DObjectMgr are empty and then shut them both down.
|
||||
*/
|
||||
public void shutdown ()
|
||||
public void harshShutdown ()
|
||||
{
|
||||
// stick a bogus object on the event queue to ensure that the mgr
|
||||
// wakes up and smells the coffee
|
||||
_evqueue.append(new ShutdownEvent());
|
||||
postUnit(new Runnable() {
|
||||
public void run () {
|
||||
_running = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -568,6 +565,15 @@ public class PresentsDObjectMgr
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should not need to be called except by the invoker during shutdown
|
||||
* to ensure that things are proceeding smoothly.
|
||||
*/
|
||||
public boolean queueIsEmpty ()
|
||||
{
|
||||
return !_evqueue.hasElements();
|
||||
}
|
||||
|
||||
protected synchronized boolean isRunning ()
|
||||
{
|
||||
return _running;
|
||||
@@ -768,21 +774,6 @@ public class PresentsDObjectMgr
|
||||
protected int _action;
|
||||
}
|
||||
|
||||
protected class ShutdownEvent extends DEvent
|
||||
{
|
||||
public ShutdownEvent ()
|
||||
{
|
||||
super(0); // target the bogus object
|
||||
}
|
||||
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing doing!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers our event helper methods.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: PresentsServer.java,v 1.34 2003/03/31 04:11:01 mdb Exp $
|
||||
// $Id: PresentsServer.java,v 1.35 2003/08/08 03:11:55 ray Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
@@ -247,8 +247,8 @@ public class PresentsServer
|
||||
});
|
||||
|
||||
// finally shut down the invoker and distributed object manager
|
||||
// (The invoker does both for us.)
|
||||
invoker.shutdown();
|
||||
omgr.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: Invoker.java,v 1.7 2003/04/10 21:04:55 mdb Exp $
|
||||
// $Id: Invoker.java,v 1.8 2003/08/08 03:11:55 ray Exp $
|
||||
|
||||
package com.threerings.presents.util;
|
||||
|
||||
@@ -115,55 +115,47 @@ public class Invoker extends LoopingThread
|
||||
public void iterate ()
|
||||
{
|
||||
// pop the next item off of the queue
|
||||
Object unit = _queue.get();
|
||||
Unit unit = (Unit) _queue.get();
|
||||
|
||||
// if it's a unit, we invoke it
|
||||
if (unit instanceof Runnable) {
|
||||
long start;
|
||||
long start;
|
||||
if (PERF_TRACK) {
|
||||
start = System.currentTimeMillis();
|
||||
_unitsRun++;
|
||||
}
|
||||
|
||||
try {
|
||||
if (unit.invoke()) {
|
||||
// if it returned true, we post it to the dobjmgr
|
||||
// thread to invoke the result processing
|
||||
_omgr.postUnit(unit);
|
||||
}
|
||||
|
||||
// track some performance metrics
|
||||
if (PERF_TRACK) {
|
||||
start = System.currentTimeMillis();
|
||||
_unitsRun++;
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
Object key = unit.getClass();
|
||||
|
||||
Histogram histo = (Histogram)_tracker.get(key);
|
||||
if (histo == null) {
|
||||
// track in buckets of 50ms up to 500ms
|
||||
_tracker.put(key, histo = new Histogram(0, 50, 10));
|
||||
}
|
||||
histo.addValue((int)duration);
|
||||
}
|
||||
|
||||
try {
|
||||
if (((Unit)unit).invoke()) {
|
||||
// if it returned true, we post it to the dobjmgr
|
||||
// thread to invoke the result processing
|
||||
_omgr.postUnit((Runnable)unit);
|
||||
}
|
||||
|
||||
// track some performance metrics
|
||||
if (PERF_TRACK) {
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
Object key = unit.getClass();
|
||||
|
||||
Histogram histo = (Histogram)_tracker.get(key);
|
||||
if (histo == null) {
|
||||
// track in buckets of 50ms up to 500ms
|
||||
_tracker.put(key, histo = new Histogram(0, 50, 10));
|
||||
}
|
||||
histo.addValue((int)duration);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Invocation unit failed [unit=" + unit + "].");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
|
||||
} else {
|
||||
// if it's not a runnable, it was just an object posted to our
|
||||
// queue to wake us up and tell us to go away
|
||||
_running = false;
|
||||
} catch (Exception e) {
|
||||
Log.warning("Invocation unit failed [unit=" + unit + "].");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
/**
|
||||
* Will do a sophisticated shutdown of both itself and the DObjectManager
|
||||
* thread.
|
||||
*/
|
||||
public void shutdown ()
|
||||
{
|
||||
// we do some custom shutdown business: add a non-runnable to the
|
||||
// queue which, when the invoker gets to it, will cause it to shut
|
||||
// itself down
|
||||
_queue.append(new Integer(0));
|
||||
_queue.append(new ShutdownUnit());
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
@@ -182,6 +174,60 @@ public class Invoker extends LoopingThread
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This unit gets posted back and forth between the invoker and DObjectMgr
|
||||
* until both of their queues are empty and they can both be safely
|
||||
* shutdown.
|
||||
*/
|
||||
protected class ShutdownUnit extends Unit
|
||||
{
|
||||
// run on the invoker thread
|
||||
public boolean invoke ()
|
||||
{
|
||||
// if the invoker queue is not empty, we put ourselves back on it
|
||||
if (_queue.hasElements()) {
|
||||
System.err.println("invoker not empty");
|
||||
postUnit(this);
|
||||
return false;
|
||||
|
||||
} else {
|
||||
// the invoker is empty, let's go over to the omgr
|
||||
System.err.println("invoker empty, passing");
|
||||
_passCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// run on the dobj thread
|
||||
public void handleResult ()
|
||||
{
|
||||
// if the queue isn't empty, re-post
|
||||
if (!_omgr.queueIsEmpty()) {
|
||||
_omgr.postUnit(this);
|
||||
|
||||
// if both queues are empty, or we've passed 50 times, end it all
|
||||
} else if (!_queue.hasElements() || (_passCount >= 50)) {
|
||||
// shut it down!
|
||||
_omgr.harshShutdown(); // end the dobj thread
|
||||
// and since we're ending the invoker from the dobjmgr
|
||||
// we need to post one last event to the invoker
|
||||
postUnit(new Unit() {
|
||||
public boolean invoke () {
|
||||
_running = false; // end this thread
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// otherwise, we need to pass back to the invoker
|
||||
} else {
|
||||
postUnit(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** The number of times we've been passed to the object manager. */
|
||||
protected int _passCount = 0;
|
||||
}
|
||||
|
||||
/** The invoker's queue of units to be executed. */
|
||||
protected Queue _queue = new Queue();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user