Widened, added a workaround for a "doesn't actually break anything and is too

complex to properly fix right now" bug.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4713 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2007-05-18 02:46:47 +00:00
parent c2fb8f99c7
commit 0c90344e6b
4 changed files with 62 additions and 50 deletions
@@ -71,8 +71,8 @@ public abstract class DEvent implements Streamable
* @exception ObjectAccessException thrown if there is any problem applying the event to the
* object (invalid attribute, etc.).
*
* @return true if the object manager should go on to notify the object's subscribers of this
* event, false if the event should be treated silently and the subscribers should not be
* @return true if the object manager should go on to notify the object's listeners of this
* event, false if the event should be treated silently and the listeners should not be
* notified.
*/
public abstract boolean applyToObject (DObject target)
@@ -26,22 +26,20 @@ import com.samskivert.util.StringUtil;
import com.threerings.presents.Log;
/**
* An entry added event is dispatched when an entry is added to a {@link
* DSet} attribute of a distributed entry. It can also be constructed to
* request the addition of an entry to a set and posted to the dobjmgr.
* An entry added event is dispatched when an entry is added to a {@link DSet} attribute of a
* distributed entry. It can also be constructed to request the addition of an entry to a set and
* posted to the dobjmgr.
*
* @see DObjectManager#postEvent
*/
public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
{
/**
* Constructs a new entry added event on the specified target object
* with the supplied set attribute name and entry to add.
* Constructs a new entry added event on the specified target object with the supplied set
* attribute name and entry to add.
*
* @param targetOid the object id of the object to whose set we will
* add an entry.
* @param name the name of the attribute to which to add the specified
* entry.
* @param targetOid the object id of the object to whose set we will add an entry.
* @param name the name of the attribute to which to add the specified entry.
* @param entry the entry to add to the set attribute.
*/
public EntryAddedEvent (int targetOid, String name, T entry)
@@ -50,11 +48,9 @@ public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
}
/**
* Used when the distributed object already added the entry before
* generating the event.
* Used when the distributed object already added the entry before generating the event.
*/
public EntryAddedEvent (int targetOid, String name, T entry,
boolean alreadyApplied)
public EntryAddedEvent (int targetOid, String name, T entry, boolean alreadyApplied)
{
super(targetOid, name);
_entry = entry;
@@ -62,8 +58,8 @@ public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
}
/**
* Constructs a blank instance of this event in preparation for
* unserialization from the network.
* Constructs a blank instance of this event in preparation for unserialization from the
* network.
*/
public EntryAddedEvent ()
{
@@ -86,7 +82,31 @@ public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
if (!_alreadyApplied) {
boolean added = target.getSet(_name).add(_entry);
if (!added) {
Log.warning("Duplicate entry found [event=" + this + "].");
// If this entry is already in the set, then don't notify our listeners of the
// event add, because nothing was actually added; the DSet will have already
// complained; this happens occasionally due to a race condition between client
// object subscription and set addition, for example, the follow sequence of events
// can take place:
//
// 1. SUBSCRIBE arrives from client, AccessObjectEvent posted;
//
// 2. addToSet() called on server, value immediately added to set and
// EntryAddedEvent is posted;
//
// 3. AccessObjectEvent processed; client is added to proxy subscriber list,
// DObject serialized and sent to client; client receives object which already has
// the entry in the set;
//
// 4. EntryAddedEvent processed, client is a subscriber so it is forwarded along;
// when it arrives at the client, we find ourselves in this situation.
//
// Fixing this would require either a) giving up immediate adding to the DSet when
// an event is posted, but we add/update immediately because it makes our lives
// *vastly* simpler in a thousand other cases, or b) doing some magic in the DSet
// where the server "sees" the new entry added, but if the DSet is serialized
// before the EntryAddedEvent comes through to "commit" that entry it is not
// included. This is probably a good idea and maybe we'll do it sometime.
return false;
}
}
return true;
@@ -111,8 +131,7 @@ public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
protected T _entry;
/** Used when this event is generated on the authoritative server
* where object changes are made immediately. This lets us know not to
* apply ourselves when we're actually dispatched. */
/** Used when this event is generated on the authoritative server where object changes are made
* immediately. This lets us know not to apply ourselves when we're actually dispatched. */
protected transient boolean _alreadyApplied;
}
@@ -24,28 +24,24 @@ package com.threerings.presents.dobj;
import com.threerings.presents.Log;
/**
* An entry removed event is dispatched when an entry is removed from a
* {@link DSet} attribute of a distributed object. It can also be
* constructed to request the removal of an entry from a set and posted to
* the dobjmgr.
* An entry removed event is dispatched when an entry is removed from a {@link DSet} attribute of a
* distributed object. It can also be constructed to request the removal of an entry from a set and
* posted to the dobjmgr.
*
* @see DObjectManager#postEvent
*/
public class EntryRemovedEvent<T extends DSet.Entry> extends NamedEvent
{
/**
* Constructs a new entry removed event on the specified target object
* with the supplied set attribute name and entry key to remove.
* Constructs a new entry removed event on the specified target object with the supplied set
* attribute name and entry key to remove.
*
* @param targetOid the object id of the object from whose set we will
* remove an entry.
* @param name the name of the attribute from which to remove the
* specified entry.
* @param targetOid the object id of the object from whose set we will remove an entry.
* @param name the name of the attribute from which to remove the specified entry.
* @param key the entry key that identifies the entry to remove.
* @param oldEntry the previous value of the entry.
*/
public EntryRemovedEvent (int targetOid, String name, Comparable key,
T oldEntry)
public EntryRemovedEvent (int targetOid, String name, Comparable key, T oldEntry)
{
super(targetOid, name);
_key = key;
@@ -53,8 +49,8 @@ public class EntryRemovedEvent<T extends DSet.Entry> extends NamedEvent
}
/**
* Constructs a blank instance of this event in preparation for
* unserialization from the network.
* Constructs a blank instance of this event in preparation for unserialization from the
* network.
*/
public EntryRemovedEvent ()
{
@@ -88,8 +84,7 @@ public class EntryRemovedEvent<T extends DSet.Entry> extends NamedEvent
_oldEntry = set.removeKey(_key);
if (_oldEntry == null) {
// complain if there was actually nothing there
Log.warning("No matching entry to remove [key=" + _key +
", set=" + set + "].");
Log.warning("No matching entry to remove [key=" + _key + ", set=" + set + "].");
return false;
}
}
@@ -113,6 +108,7 @@ public class EntryRemovedEvent<T extends DSet.Entry> extends NamedEvent
}
protected Comparable _key;
@SuppressWarnings("unchecked")
protected transient T _oldEntry = (T)UNSET_OLD_ENTRY;
}
@@ -26,22 +26,19 @@ import com.samskivert.util.StringUtil;
import com.threerings.presents.Log;
/**
* An entry updated event is dispatched when an entry of a {@link DSet} is
* updated. It can also be constructed to request the update of an entry
* and posted to the dobjmgr.
* An entry updated event is dispatched when an entry of a {@link DSet} is updated. It can also be
* constructed to request the update of an entry and posted to the dobjmgr.
*
* @see DObjectManager#postEvent
*/
public class EntryUpdatedEvent<T extends DSet.Entry> extends NamedEvent
{
/**
* Constructs a new entry updated event on the specified target object
* for the specified set name and with the supplied updated entry.
* Constructs a new entry updated event on the specified target object for the specified set
* name and with the supplied updated entry.
*
* @param targetOid the object id of the object to whose set we will
* add an entry.
* @param name the name of the attribute in which to update the
* specified entry.
* @param targetOid the object id of the object to whose set we will add an entry.
* @param name the name of the attribute in which to update the specified entry.
* @param entry the entry to update.
* @param oldEntry the previous value of the entry.
*/
@@ -53,8 +50,8 @@ public class EntryUpdatedEvent<T extends DSet.Entry> extends NamedEvent
}
/**
* Constructs a blank instance of this event in preparation for
* unserialization from the network.
* Constructs a blank instance of this event in preparation for unserialization from the
* network.
*/
public EntryUpdatedEvent ()
{
@@ -89,8 +86,7 @@ public class EntryUpdatedEvent<T extends DSet.Entry> extends NamedEvent
_oldEntry = set.update(_entry);
if (_oldEntry == null) {
// complain if we didn't update anything
Log.warning("No matching entry to update [entry=" + this +
", set=" + set + "].");
Log.warning("No matching entry to update [entry=" + this + ", set=" + set + "].");
return false;
}
}
@@ -115,6 +111,7 @@ public class EntryUpdatedEvent<T extends DSet.Entry> extends NamedEvent
}
protected T _entry;
@SuppressWarnings("unchecked")
protected transient T _oldEntry = (T)UNSET_OLD_ENTRY;
}