Let's take invokdeNodeRequest the final distance; NodeRequest allows each peer to submit a result, so let's pass those results back to the caller instead of throwing them away. With this, we should be able to stop shoving all complex peer operations into PeerManager subclasses, and instead sprinkling them as NodeRequests in the sub-packages in which they belong.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6141 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Par Winzell
2010-09-07 19:08:26 +00:00
parent a9c4b051e0
commit 5365b53ee6
2 changed files with 87 additions and 13 deletions
@@ -0,0 +1,32 @@
package com.threerings.presents.peer.server;
import java.util.Map;
import com.threerings.presents.client.InvocationService;
/**
* Communicates the {@link NodeRequestsResult} of a {@link PeerManager.NodeRequest} sent to one
* or more peer nodes.
*/
public interface
NodeRequestsListener<T> extends InvocationService.InvocationListener
{
/**
* Called upon the successful completion of {@link PeerManager#invokeNodeRequest}, regardless
* of how many nodes were contacted or applicable.
*/
public void requestsProcessed (NodeRequestsResult<T> result);
/**
* Contains the result of a {@link PeerManager.NodeRequest} sent to one or more peer nodes.
* Any node that returned true for {@link PeerManager.NodeRequest#isApplicable} will appear
* in either {@link #getNodeResults()} or {@link #getNodeErrors()}. The wasDropped() method
* will return true iff both mappings are empty.
*/
public interface NodeRequestsResult<T>
{
public Map<String, T> getNodeResults ();
public Map<String, String> getNodeErrors ();
boolean wasDropped ();
}
}
@@ -471,15 +471,13 @@ public abstract class PeerManager
* If any one node reports failure, this function reports failure. If all nodes report success, * If any one node reports failure, this function reports failure. If all nodes report success,
* this function will report success. * this function will report success.
*/ */
public void invokeNodeRequest ( public <T> void invokeNodeRequest (final NodeRequest request, final NodeRequestsListener<T> listener)
final NodeRequest request, final InvocationService.ConfirmListener listener,
final Runnable onDropped)
{ {
// if we're not on the dobjmgr thread, get there // if we're not on the dobjmgr thread, get there
if (!_omgr.isDispatchThread()) { if (!_omgr.isDispatchThread()) {
_omgr.postRunnable(new Runnable() { _omgr.postRunnable(new Runnable() {
public void run () { public void run () {
invokeNodeRequest(request, listener, onDropped); invokeNodeRequest(request, listener);
} }
}); });
return; return;
@@ -498,24 +496,32 @@ public abstract class PeerManager
nodes.add(peer.getNodeName()); nodes.add(peer.getNodeName());
} }
} }
if (nodes.isEmpty() && onDropped != null) { if (nodes.isEmpty()) {
onDropped.run(); listener.requestsProcessed(new NodeRequestsResultImpl());
return; return;
} }
final Map<String, T> results = Maps.newHashMap();
final Map<String, String> failures = Maps.newHashMap();
for (final String node : nodes) { for (final String node : nodes) {
invokeNodeRequest(node, requestBytes, new InvocationService.ResultListener() { invokeNodeRequest(node, requestBytes, new InvocationService.ResultListener() {
public void requestProcessed (Object result) { public void requestProcessed (Object result) {
// check off this node's successful response // check off this node's successful response
nodes.remove(node); @SuppressWarnings("unchecked")
if (nodes.isEmpty()) { T castResult = (T) result;
// if all nodes have responded in the affirmative, let caller know results.put(node, castResult);
listener.requestProcessed(); nodeDone(node);
}
} }
public void requestFailed (String cause) { public void requestFailed (String cause) {
// let the caller know a node failed failures.put(node, cause);
listener.requestFailed(cause); nodeDone(node);
}
protected void nodeDone (String node) {
nodes.remove(node);
if (nodes.isEmpty()) {
// if all nodes have responded, let caller know
listener.requestsProcessed(new NodeRequestsResultImpl(results, failures));
}
} }
}); });
} }
@@ -1520,6 +1526,42 @@ public abstract class PeerManager
protected long _startStamp = System.currentTimeMillis(); protected long _startStamp = System.currentTimeMillis();
} }
protected static class NodeRequestsResultImpl<T>
implements NodeRequestsListener.NodeRequestsResult<T>
{
public NodeRequestsResultImpl (Map<String, T> results, Map<String, String> errors)
{
_results = Maps.newHashMap(results);
_errors = Maps.newHashMap(errors);
}
public NodeRequestsResultImpl ()
{
this(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
}
@Override public Map<String, T> getNodeResults ()
{
return _results;
}
@Override
public Map<String, String> getNodeErrors ()
{
return _errors;
}
@Override
public boolean wasDropped ()
{
return _results.isEmpty() && _errors.isEmpty();
}
protected Map<String, T> _results;
protected Map<String, String> _errors;
}
/** Extracts the node object from the supplied peer. */ /** Extracts the node object from the supplied peer. */
protected static final Function<PeerNode, NodeObject> GET_NODE_OBJECT = protected static final Function<PeerNode, NodeObject> GET_NODE_OBJECT =
new Function<PeerNode, NodeObject>() { new Function<PeerNode, NodeObject>() {