Replaced old wacked-in-head system with proper reference counting for
client objects. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1989 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientObject.dobj,v 1.2 2002/09/19 23:36:59 mdb Exp $
|
// $Id: ClientObject.dobj,v 1.3 2002/11/26 02:14:24 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.data;
|
package com.threerings.presents.data;
|
||||||
|
|
||||||
import com.threerings.presents.dobj.DObject;
|
import com.threerings.presents.dobj.DObject;
|
||||||
import com.threerings.presents.dobj.DSet;
|
import com.threerings.presents.dobj.DSet;
|
||||||
|
|
||||||
|
import com.threerings.presents.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every client in the system has an associated client object to which
|
* Every client in the system has an associated client object to which
|
||||||
* only they subscribe. The client object can be used to deliver messages
|
* only they subscribe. The client object can be used to deliver messages
|
||||||
@@ -29,4 +31,32 @@ public class ClientObject extends DObject
|
|||||||
{
|
{
|
||||||
return "(" + getOid() + ")";
|
return "(" + getOid() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for reference counting client objects, adds a reference to
|
||||||
|
* this object.
|
||||||
|
*/
|
||||||
|
public synchronized void reference ()
|
||||||
|
{
|
||||||
|
_references++;
|
||||||
|
// Log.info("Incremented references [who=" + who() +
|
||||||
|
// ", refs=" + _references + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for reference counting client objects, releases a reference to
|
||||||
|
* this object.
|
||||||
|
*
|
||||||
|
* @return true if the object has remaining references, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean release ()
|
||||||
|
{
|
||||||
|
// Log.info("Decremented references [who=" + who() +
|
||||||
|
// ", refs=" + (_references-1) + "].");
|
||||||
|
return (--_references > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to reference count resolved client objects. */
|
||||||
|
protected transient int _references;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientObject.java,v 1.4 2002/09/19 23:36:59 mdb Exp $
|
// $Id: ClientObject.java,v 1.5 2002/11/26 02:14:24 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.data;
|
package com.threerings.presents.data;
|
||||||
|
|
||||||
import com.threerings.presents.dobj.DObject;
|
import com.threerings.presents.dobj.DObject;
|
||||||
import com.threerings.presents.dobj.DSet;
|
import com.threerings.presents.dobj.DSet;
|
||||||
|
|
||||||
|
import com.threerings.presents.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every client in the system has an associated client object to which
|
* Every client in the system has an associated client object to which
|
||||||
* only they subscribe. The client object can be used to deliver messages
|
* only they subscribe. The client object can be used to deliver messages
|
||||||
@@ -33,6 +35,34 @@ public class ClientObject extends DObject
|
|||||||
return "(" + getOid() + ")";
|
return "(" + getOid() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for reference counting client objects, adds a reference to
|
||||||
|
* this object.
|
||||||
|
*/
|
||||||
|
public synchronized void reference ()
|
||||||
|
{
|
||||||
|
_references++;
|
||||||
|
// Log.info("Incremented references [who=" + who() +
|
||||||
|
// ", refs=" + _references + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for reference counting client objects, releases a reference to
|
||||||
|
* this object.
|
||||||
|
*
|
||||||
|
* @return true if the object has remaining references, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean release ()
|
||||||
|
{
|
||||||
|
// Log.info("Decremented references [who=" + who() +
|
||||||
|
// ", refs=" + (_references-1) + "].");
|
||||||
|
return (--_references > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to reference count resolved client objects. */
|
||||||
|
protected transient int _references;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests that the specified entry be added to the
|
* Requests that the specified entry be added to the
|
||||||
* <code>receivers</code> set. The set will not change until the event is
|
* <code>receivers</code> set. The set will not change until the event is
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientManager.java,v 1.26 2002/11/05 02:17:56 mdb Exp $
|
// $Id: ClientManager.java,v 1.27 2002/11/26 02:14:25 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.server;
|
package com.threerings.presents.server;
|
||||||
|
|
||||||
@@ -135,7 +135,9 @@ public class ClientManager
|
|||||||
* If the client object is already resolved, the request will be
|
* If the client object is already resolved, the request will be
|
||||||
* processed immediately, otherwise the appropriate client object will
|
* processed immediately, otherwise the appropriate client object will
|
||||||
* be instantiated and populated by the registered client resolver
|
* be instantiated and populated by the registered client resolver
|
||||||
* (which may involve talking to databases).
|
* (which may involve talking to databases). <em>Note:</em> this
|
||||||
|
* <b>must</b> be paired with a call to {@link #releaseClientObject}
|
||||||
|
* when the caller is finished with the client object.
|
||||||
*/
|
*/
|
||||||
public synchronized void resolveClientObject (
|
public synchronized void resolveClientObject (
|
||||||
String username, ClientResolutionListener listener)
|
String username, ClientResolutionListener listener)
|
||||||
@@ -144,6 +146,7 @@ public class ClientManager
|
|||||||
String key = toKey(username);
|
String key = toKey(username);
|
||||||
ClientObject clobj = (ClientObject)_objmap.get(key);
|
ClientObject clobj = (ClientObject)_objmap.get(key);
|
||||||
if (clobj != null) {
|
if (clobj != null) {
|
||||||
|
clobj.reference();
|
||||||
listener.clientResolved(username, clobj);
|
listener.clientResolved(username, clobj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -189,67 +192,34 @@ public class ClientManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an entity resolves a client object outside the scope of a normal
|
* Releases a client object that was obtained via a call to {@link
|
||||||
* client session, it should call this to unmap the client object when
|
* #resolveClientObject}. If this caller is the last reference, the
|
||||||
* it's finished. This won't actually unmap the client if someone came
|
* object will be flushed and destroyed.
|
||||||
* along and started a session for that client in the meanwhile, but
|
|
||||||
* if it does unmap the client it will also destroy the client object
|
|
||||||
* (finishing the job, as it were).
|
|
||||||
*/
|
*/
|
||||||
public synchronized void unmapClientObject (String username)
|
public void releaseClientObject (String username)
|
||||||
{
|
{
|
||||||
// we only remove the mapping if there's not a session in progress
|
|
||||||
// (which is indicated by an entry in the locks table)
|
|
||||||
String key = toKey(username);
|
String key = toKey(username);
|
||||||
if (_locks.contains(key)) {
|
ClientObject clobj = (ClientObject)_objmap.get(key);
|
||||||
|
if (clobj == null) {
|
||||||
|
Log.warning("Requested to release unmapped client object " +
|
||||||
|
"[username=" + username + "].");
|
||||||
|
Thread.dumpStack();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientObject clobj = (ClientObject)_objmap.remove(key);
|
// decrement the reference count and stop here if there are
|
||||||
if (clobj != null) {
|
// remaining references
|
||||||
PresentsServer.omgr.destroyObject(clobj.getOid());
|
if (clobj.release()) {
|
||||||
} else {
|
return;
|
||||||
Log.warning("Requested to unmap non-existent client object " +
|
|
||||||
"[username=" + username + "].");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
Log.debug("Destroying client " + clobj.who() + ".");
|
||||||
* When a client object becomes part of an active session, this method
|
|
||||||
* should be called to ensure that it is not unloaded by any entities
|
|
||||||
* that temporarily resolve and release the object. This is called
|
|
||||||
* automatically when a real user starts a session by establishing a
|
|
||||||
* network connection with the server. If a client session is managed
|
|
||||||
* via some other mechanism (bots managed by the server, for example),
|
|
||||||
* this method and its corresponding {@link #releaseClientObject}
|
|
||||||
* should be called at the beginning and end of the faked client
|
|
||||||
* session respectively.
|
|
||||||
*/
|
|
||||||
public synchronized void lockClientObject (String username)
|
|
||||||
{
|
|
||||||
String key = toKey(username);
|
|
||||||
if (_locks.contains(key)) {
|
|
||||||
Log.warning("Requested to lock already locked user " +
|
|
||||||
"[username=" + username + "].");
|
|
||||||
Thread.dumpStack();
|
|
||||||
|
|
||||||
} else {
|
// we're all clear to go; remove the mapping
|
||||||
_locks.add(key);
|
_objmap.remove(key);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// and destroy the object itself
|
||||||
* Releases a client object when their session has ended.
|
PresentsServer.omgr.destroyObject(clobj.getOid());
|
||||||
*
|
|
||||||
* @see #lockClientObject
|
|
||||||
*/
|
|
||||||
public synchronized void releaseClientObject (String username)
|
|
||||||
{
|
|
||||||
if (!_locks.remove(toKey(username))) {
|
|
||||||
Log.warning("Requested to unlock a user that was not locked " +
|
|
||||||
"[username=" + username + "].");
|
|
||||||
Thread.dumpStack();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
@@ -355,21 +325,12 @@ public class ClientManager
|
|||||||
if (rc == null) {
|
if (rc == null) {
|
||||||
Log.warning("Unregistered client ended session " + client + ".");
|
Log.warning("Unregistered client ended session " + client + ".");
|
||||||
Thread.dumpStack();
|
Thread.dumpStack();
|
||||||
|
|
||||||
// if they weren't in the username mapping, bail out now
|
|
||||||
// because the subsequent unmappings would just fail if we
|
|
||||||
// tried to do them for an unmapped client
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else if (rc != client) {
|
} else if (rc != client) {
|
||||||
Log.warning("Different clients with same username!? " +
|
Log.warning("Different clients with same username!? " +
|
||||||
"[c1=" + rc + ", c2=" + client + "].");
|
"[c1=" + rc + ", c2=" + client + "].");
|
||||||
} else {
|
} else {
|
||||||
Log.info("Ending session " + client + ".");
|
Log.info("Ending session " + client + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmap (and destroy) the client object
|
|
||||||
unmapClientObject(username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientResolver.java,v 1.1 2002/03/05 05:33:25 mdb Exp $
|
// $Id: ClientResolver.java,v 1.2 2002/11/26 02:14:25 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.server;
|
package com.threerings.presents.server;
|
||||||
|
|
||||||
@@ -99,6 +99,8 @@ public class ClientResolver extends Invoker.Unit
|
|||||||
ClientResolutionListener crl = (ClientResolutionListener)
|
ClientResolutionListener crl = (ClientResolutionListener)
|
||||||
_listeners.get(i);
|
_listeners.get(i);
|
||||||
try {
|
try {
|
||||||
|
// add a reference for each listener
|
||||||
|
_clobj.reference();
|
||||||
crl.clientResolved(_username, _clobj);
|
crl.clientResolved(_username, _clobj);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.warning("Client resolution listener choked during " +
|
Log.warning("Client resolution listener choked during " +
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: PresentsClient.java,v 1.44 2002/11/05 05:47:36 mdb Exp $
|
// $Id: PresentsClient.java,v 1.45 2002/11/26 02:14:25 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.server;
|
package com.threerings.presents.server;
|
||||||
|
|
||||||
@@ -154,20 +154,13 @@ public class PresentsClient
|
|||||||
// call down to any derived classes
|
// call down to any derived classes
|
||||||
clientObjectWillChange(_clobj, clobj);
|
clientObjectWillChange(_clobj, clobj);
|
||||||
|
|
||||||
// release our old client object
|
// release our old client object; this will destroy it
|
||||||
_cmgr.releaseClientObject(_username);
|
_cmgr.releaseClientObject(_username);
|
||||||
|
|
||||||
// unmap the old client object; this will destroy it and
|
|
||||||
// clear out our username mapping
|
|
||||||
_cmgr.unmapClientObject(_username);
|
|
||||||
|
|
||||||
// update our internal fields
|
// update our internal fields
|
||||||
_username = username;
|
_username = username;
|
||||||
_clobj = clobj;
|
_clobj = clobj;
|
||||||
|
|
||||||
// lock our new client object
|
|
||||||
_cmgr.lockClientObject(_username);
|
|
||||||
|
|
||||||
// call down to any derived classes
|
// call down to any derived classes
|
||||||
clientObjectDidChange(_clobj);
|
clientObjectDidChange(_clobj);
|
||||||
|
|
||||||
@@ -234,10 +227,6 @@ public class PresentsClient
|
|||||||
// obtain our starting username
|
// obtain our starting username
|
||||||
assignStartingUsername();
|
assignStartingUsername();
|
||||||
|
|
||||||
// obtain a lock for our username->client object mapping while we
|
|
||||||
// have an active session
|
|
||||||
cmgr.lockClientObject(_username);
|
|
||||||
|
|
||||||
// resolve our client object before we get fully underway
|
// resolve our client object before we get fully underway
|
||||||
cmgr.resolveClientObject(_username, this);
|
cmgr.resolveClientObject(_username, this);
|
||||||
|
|
||||||
@@ -448,11 +437,10 @@ public class PresentsClient
|
|||||||
// about to generate
|
// about to generate
|
||||||
clearSubscrips();
|
clearSubscrips();
|
||||||
|
|
||||||
// release our locked client object
|
// release (and destroy) our client object
|
||||||
_cmgr.releaseClientObject(_username);
|
_cmgr.releaseClientObject(_username);
|
||||||
|
|
||||||
// then let the client manager know what's up (it will take care
|
// let the client manager know that we're audi 5000
|
||||||
// of destroying our client object for us)
|
|
||||||
_cmgr.clientDidEndSession(this);
|
_cmgr.clientDidEndSession(this);
|
||||||
|
|
||||||
// clear out the client object so that we know the session is over
|
// clear out the client object so that we know the session is over
|
||||||
|
|||||||
Reference in New Issue
Block a user