- Monitor logins to other nodes, boot any local sessions with the same
authentication name. - Use new (ca. 2002) pattern of creating an overridable listener, rather than making the whole class a listener. Mdb told me to add this at the msoy level, but I think it belongs here. Presents simply expects a user to be in one place. It also occurs to me that we probably want something more sophisticated: there may be unpersisted data connected to the session that should be flushed prior to the session starting on another node. We may want something like a lock when users log-in, so that other nodes can terminate the session and flush any persistent data FIRST. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5635 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -984,6 +984,19 @@ public abstract class PeerManager
|
|||||||
return new PeerCreds(_nodeName, _sharedSecret);
|
return new PeerCreds(_nodeName, _sharedSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when we hear about a client logging on to another node.
|
||||||
|
*/
|
||||||
|
protected void clientLoggedOnOtherNode (String nodeName, ClientInfo clinfo)
|
||||||
|
{
|
||||||
|
PresentsSession session = _clmgr.getClient(clinfo.username);
|
||||||
|
if (session != null) {
|
||||||
|
log.info("Booting user that has connected on another node",
|
||||||
|
"username", clinfo.username, "otherNode", nodeName);
|
||||||
|
session.endSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a peer connects to this server.
|
* Called when a peer connects to this server.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,8 +35,14 @@ import com.threerings.presents.dobj.AttributeChangeListener;
|
|||||||
import com.threerings.presents.dobj.AttributeChangedEvent;
|
import com.threerings.presents.dobj.AttributeChangedEvent;
|
||||||
import com.threerings.presents.dobj.DEvent;
|
import com.threerings.presents.dobj.DEvent;
|
||||||
import com.threerings.presents.dobj.DObject;
|
import com.threerings.presents.dobj.DObject;
|
||||||
|
import com.threerings.presents.dobj.DSet;
|
||||||
|
import com.threerings.presents.dobj.EntryAddedEvent;
|
||||||
|
import com.threerings.presents.dobj.EntryRemovedEvent;
|
||||||
|
import com.threerings.presents.dobj.EntryUpdatedEvent;
|
||||||
import com.threerings.presents.dobj.ObjectAccessException;
|
import com.threerings.presents.dobj.ObjectAccessException;
|
||||||
|
import com.threerings.presents.dobj.SetListener;
|
||||||
import com.threerings.presents.dobj.Subscriber;
|
import com.threerings.presents.dobj.Subscriber;
|
||||||
|
import com.threerings.presents.peer.data.ClientInfo;
|
||||||
import com.threerings.presents.peer.data.NodeObject;
|
import com.threerings.presents.peer.data.NodeObject;
|
||||||
import com.threerings.presents.peer.net.PeerBootstrapData;
|
import com.threerings.presents.peer.net.PeerBootstrapData;
|
||||||
import com.threerings.presents.peer.server.persist.NodeRecord;
|
import com.threerings.presents.peer.server.persist.NodeRecord;
|
||||||
@@ -49,7 +55,7 @@ import static com.threerings.presents.Log.log;
|
|||||||
* Contains all runtime information for one of our peer nodes.
|
* Contains all runtime information for one of our peer nodes.
|
||||||
*/
|
*/
|
||||||
public class PeerNode
|
public class PeerNode
|
||||||
implements ClientObserver, Subscriber<NodeObject>, AttributeChangeListener
|
implements ClientObserver, Subscriber<NodeObject>
|
||||||
{
|
{
|
||||||
/** This peer's node object. */
|
/** This peer's node object. */
|
||||||
public NodeObject nodeobj;
|
public NodeObject nodeobj;
|
||||||
@@ -190,6 +196,8 @@ public class PeerNode
|
|||||||
public void clientDidLogoff (Client client)
|
public void clientDidLogoff (Client client)
|
||||||
{
|
{
|
||||||
_peermgr.disconnectedFromPeer(this);
|
_peermgr.disconnectedFromPeer(this);
|
||||||
|
nodeobj.removeListener(_listener);
|
||||||
|
_listener = null;
|
||||||
nodeobj = null;
|
nodeobj = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +212,7 @@ public class PeerNode
|
|||||||
{
|
{
|
||||||
// listen for lock and cache updates
|
// listen for lock and cache updates
|
||||||
nodeobj = object;
|
nodeobj = object;
|
||||||
nodeobj.addListener(this);
|
nodeobj.addListener(_listener = createListener());
|
||||||
|
|
||||||
_peermgr.connectedToPeer(this);
|
_peermgr.connectedToPeer(this);
|
||||||
}
|
}
|
||||||
@@ -216,49 +224,6 @@ public class PeerNode
|
|||||||
"[peer=" + _record + ", cause=" + cause + "].");
|
"[peer=" + _record + ", cause=" + cause + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface AttributeChangeListener
|
|
||||||
public void attributeChanged (AttributeChangedEvent event)
|
|
||||||
{
|
|
||||||
String name = event.getName();
|
|
||||||
if (name.equals(NodeObject.ACQUIRING_LOCK)) {
|
|
||||||
NodeObject.Lock lock = nodeobj.acquiringLock;
|
|
||||||
PeerManager.LockHandler handler = _peermgr.getLockHandler(lock);
|
|
||||||
if (handler == null) {
|
|
||||||
if (_peermgr.getNodeObject().locks.contains(lock)) {
|
|
||||||
log.warning("Peer trying to acquire lock owned by this node " +
|
|
||||||
"[lock=" + lock + ", node=" + _record.nodeName + "].");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_peermgr.createLockHandler(this, lock, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the other node has priority, we're done
|
|
||||||
if (hasPriority(handler.getNodeName(), _record.nodeName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this node has priority, so cancel the existing handler and take over its listeners
|
|
||||||
ResultListenerList<String> olisteners = handler.listeners;
|
|
||||||
handler.cancel();
|
|
||||||
handler = _peermgr.createLockHandler(this, lock, true);
|
|
||||||
handler.listeners = olisteners;
|
|
||||||
|
|
||||||
} else if (name.equals(NodeObject.RELEASING_LOCK)) {
|
|
||||||
NodeObject.Lock lock = nodeobj.releasingLock;
|
|
||||||
PeerManager.LockHandler handler = _peermgr.getLockHandler(lock);
|
|
||||||
if (handler == null) {
|
|
||||||
_peermgr.createLockHandler(this, lock, false);
|
|
||||||
} else {
|
|
||||||
log.warning("Received request to release resolving lock [node=" +
|
|
||||||
_record.nodeName + ", handler=" + handler + "].");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (name.equals(NodeObject.CACHE_DATA)) {
|
|
||||||
_peermgr.changedCacheData(nodeobj.cacheData.cache, nodeobj.cacheData.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the first node named has priority over the second when resolving
|
* Determines whether the first node named has priority over the second when resolving
|
||||||
* lock disputes.
|
* lock disputes.
|
||||||
@@ -275,10 +240,91 @@ public class PeerNode
|
|||||||
return new BlockingCommunicator(client);
|
return new BlockingCommunicator(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the NodeObjectListener to use. Overrideable.
|
||||||
|
*/
|
||||||
|
protected NodeObjectListener createListener ()
|
||||||
|
{
|
||||||
|
return new NodeObjectListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens to node object changes.
|
||||||
|
*/
|
||||||
|
protected class NodeObjectListener
|
||||||
|
implements AttributeChangeListener, SetListener<DSet.Entry>
|
||||||
|
{
|
||||||
|
// documentation inherited from interface AttributeChangeListener
|
||||||
|
public void attributeChanged (AttributeChangedEvent event)
|
||||||
|
{
|
||||||
|
String name = event.getName();
|
||||||
|
if (name.equals(NodeObject.ACQUIRING_LOCK)) {
|
||||||
|
NodeObject.Lock lock = nodeobj.acquiringLock;
|
||||||
|
PeerManager.LockHandler handler = _peermgr.getLockHandler(lock);
|
||||||
|
if (handler == null) {
|
||||||
|
if (_peermgr.getNodeObject().locks.contains(lock)) {
|
||||||
|
log.warning("Peer trying to acquire lock owned by this node " +
|
||||||
|
"[lock=" + lock + ", node=" + _record.nodeName + "].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_peermgr.createLockHandler(PeerNode.this, lock, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the other node has priority, we're done
|
||||||
|
if (hasPriority(handler.getNodeName(), _record.nodeName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this node has priority, so cancel the existing handler and take over
|
||||||
|
// its listeners
|
||||||
|
ResultListenerList<String> olisteners = handler.listeners;
|
||||||
|
handler.cancel();
|
||||||
|
handler = _peermgr.createLockHandler(PeerNode.this, lock, true);
|
||||||
|
handler.listeners = olisteners;
|
||||||
|
|
||||||
|
} else if (name.equals(NodeObject.RELEASING_LOCK)) {
|
||||||
|
NodeObject.Lock lock = nodeobj.releasingLock;
|
||||||
|
PeerManager.LockHandler handler = _peermgr.getLockHandler(lock);
|
||||||
|
if (handler == null) {
|
||||||
|
_peermgr.createLockHandler(PeerNode.this, lock, false);
|
||||||
|
} else {
|
||||||
|
log.warning("Received request to release resolving lock",
|
||||||
|
"node", _record.nodeName, "handler", handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (name.equals(NodeObject.CACHE_DATA)) {
|
||||||
|
_peermgr.changedCacheData(nodeobj.cacheData.cache, nodeobj.cacheData.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface SetListener
|
||||||
|
public void entryAdded (EntryAddedEvent<DSet.Entry> event)
|
||||||
|
{
|
||||||
|
String name = event.getName();
|
||||||
|
if (NodeObject.CLIENTS.equals(name)) {
|
||||||
|
_peermgr.clientLoggedOnOtherNode(getNodeName(), (ClientInfo)event.getEntry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface SetListener
|
||||||
|
public void entryUpdated (EntryUpdatedEvent<DSet.Entry> event)
|
||||||
|
{
|
||||||
|
// nada
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface SetListener
|
||||||
|
public void entryRemoved (EntryRemovedEvent<DSet.Entry> event)
|
||||||
|
{
|
||||||
|
// nada
|
||||||
|
}
|
||||||
|
} // END: class NodeObjectListener
|
||||||
|
|
||||||
protected PeerManager _peermgr;
|
protected PeerManager _peermgr;
|
||||||
protected PresentsDObjectMgr _omgr;
|
protected PresentsDObjectMgr _omgr;
|
||||||
protected ConnectionManager _conmgr;
|
protected ConnectionManager _conmgr;
|
||||||
protected NodeRecord _record;
|
protected NodeRecord _record;
|
||||||
|
protected NodeObjectListener _listener;
|
||||||
protected Client _client;
|
protected Client _client;
|
||||||
protected long _lastConnectStamp;
|
protected long _lastConnectStamp;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user