From 25717d3ccee4a4ffc1a7c0f801a6321bd0d4937a Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Mon, 4 Feb 2002 00:50:12 +0000 Subject: [PATCH] Modified distributed sets such that they can be heterogenous or homogenous, and in the latter case, they simply conserve network bandwidth by not transmitting the classname of serialized elements when transmitting themselves or element added/updated events. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@925 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/presents/dobj/DObject.java | 34 +++++-- .../com/threerings/presents/dobj/DSet.java | 96 ++++++++++++------- .../presents/dobj/EntryAddedEvent.java | 12 ++- .../presents/dobj/EntryUpdatedEvent.java | 12 ++- .../presents/dobj/io/EntryUtil.java | 13 ++- 5 files changed, 113 insertions(+), 54 deletions(-) diff --git a/src/java/com/threerings/presents/dobj/DObject.java b/src/java/com/threerings/presents/dobj/DObject.java index 45a1fb43e..4e6d0f088 100644 --- a/src/java/com/threerings/presents/dobj/DObject.java +++ b/src/java/com/threerings/presents/dobj/DObject.java @@ -1,5 +1,5 @@ // -// $Id: DObject.java,v 1.33 2002/02/03 04:38:05 mdb Exp $ +// $Id: DObject.java,v 1.34 2002/02/04 00:50:11 mdb Exp $ package com.threerings.presents.dobj; @@ -501,10 +501,18 @@ public class DObject */ protected void requestElementAdd (String name, DSet.Element elem) { - // generate an element added event - DEvent event = new ElementAddedEvent(_oid, name, elem); - // and dispatch it to our dobjmgr - _mgr.postEvent(event); + try { + DSet set = (DSet)getAttribute(name); + // generate an element added event + DEvent event = new ElementAddedEvent( + _oid, name, elem, !set.homogenous()); + // and dispatch it to our dobjmgr + _mgr.postEvent(event); + + } catch (ObjectAccessException oae) { + Log.warning("Unable to request elementAdd [name=" + name + + ", elem=" + elem + ", error=" + oae + "]."); + } } /** @@ -523,10 +531,18 @@ public class DObject */ protected void requestElementUpdate (String name, DSet.Element elem) { - // generate an element updated event - DEvent event = new ElementUpdatedEvent(_oid, name, elem); - // and dispatch it to our dobjmgr - _mgr.postEvent(event); + try { + DSet set = (DSet)getAttribute(name); + // generate an element updated event + DEvent event = new ElementUpdatedEvent( + _oid, name, elem, !set.homogenous()); + // and dispatch it to our dobjmgr + _mgr.postEvent(event); + + } catch (ObjectAccessException oae) { + Log.warning("Unable to request elementAdd [name=" + name + + ", elem=" + elem + ", error=" + oae + "]."); + } } /** Our object id. */ diff --git a/src/java/com/threerings/presents/dobj/DSet.java b/src/java/com/threerings/presents/dobj/DSet.java index 991ac33c9..18f8e99d5 100644 --- a/src/java/com/threerings/presents/dobj/DSet.java +++ b/src/java/com/threerings/presents/dobj/DSet.java @@ -1,5 +1,5 @@ // -// $Id: DSet.java,v 1.11 2001/10/16 16:43:20 mdb Exp $ +// $Id: DSet.java,v 1.12 2002/02/04 00:50:11 mdb Exp $ package com.threerings.presents.dobj; @@ -8,6 +8,8 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Iterator; +import com.samskivert.util.StringUtil; + import com.threerings.presents.Log; import com.threerings.presents.io.Streamable; @@ -17,14 +19,12 @@ import com.threerings.presents.io.Streamable; * be added to and removed from the set, requests for which will generate * events much like other distributed object fields. * - *

The sets must contain a homogenous set of objects (all of exactly - * the same type) and the master copy of the set (the one in the master - * copy of the distributed object, ie. the server copy), must be - * configured with the class object of the type of object that this set - * will contain. This allows the set to distributed updates without - * communicating the class of the object contained therein. That need only - * be communicated once when the entire containing distributed object is - * sent over the wire. + *

A set can be either homogenous, whereby the type of object to be + * contained in the set is configured before the set is used and does not + * change; or heterogenous, whereby a set can contain any type of element + * as long as it implements {@link Element}. Homogenous sets take + * advantage of their homogeneity by not transfering the classname of each + * element as it is sent over the wire. * *

Classes that wish to act as set elements must implement the {@link * com.threerings.presents.dobj.DSet.Element} interface which extends @@ -65,14 +65,23 @@ public class DSet /** * Constructs a distributed set without specifying the element - * type. This is valid if the distributed set will soon be - * unserialized or if one plans to set the element type by hand before - * using the set. + * type. The set will assume that it is heterogenous, unless a + * homogenous class type is otherwise specified via {@link + * #setElementType}. */ public DSet () { } + /** + * Returns true if this set contains only elements of exactly the same + * type, false if not. + */ + public boolean homogenous () + { + return _elementType != null; + } + /** * Indicates what type of elements will be stored in this set. This * can be called multiple times before the set is used (in the event @@ -89,22 +98,6 @@ public class DSet _elementType = elementType; } - /** - * Instantiates a blank element of the type managed by this set. This - * is used during the process of unserializing elements from the - * network. - */ - public DSet.Element newElement () - { - try { - return (Element)_elementType.newInstance(); - } catch (Exception e) { - Log.warning("Unable to instantiate element! We're hosed! " + - "[eclass=" + _elementType + "]."); - return null; - } - } - /** * Returns the number of elements in this set. */ @@ -308,7 +301,11 @@ public class DSet public void writeTo (DataOutputStream out) throws IOException { - out.writeUTF(_elementType.getName()); + if (_elementType == null) { + out.writeUTF(""); + } else { + out.writeUTF(_elementType.getName()); + } out.writeInt(_size); int elength = _elements.length; for (int i = 0; i < elength; i++) { @@ -325,10 +322,14 @@ public class DSet public void readFrom (DataInputStream in) throws IOException { - // read our element class and forName() it + // read our element class and forName() it (if we read an element + // class, we're a homogenous set; otherwise we're heterogenous) String eclass = in.readUTF(); try { - _elementType = Class.forName(eclass); + if (!StringUtil.blank(eclass)) { + _elementType = Class.forName(eclass); + } + } catch (Exception e) { String err = "Unable to instantiate element class [err=" + e + "]"; throw new IOException(err); @@ -341,12 +342,39 @@ public class DSet expand(_size); for (int i = 0; i < _size; i++) { - Element elem = newElement(); - elem.readFrom(in); - _elements[i] = elem; + _elements[i] = readElement(in); } } + /** + * Reads an element from the wire and unserializes it. Takes into + * account whether or not we're a homogenous set. + */ + public Element readElement (DataInputStream in) + throws IOException + { + try { + Element elem = null; + + // instantiate the appropriate element instance + if (_elementType != null) { + elem = (Element)_elementType.newInstance(); + } else { + elem = (Element)Class.forName(in.readUTF()).newInstance(); + } + + // unserialize it and return it + elem.readFrom(in); + return elem; + + } catch (Exception e) { + Log.warning("Unable to unserialize set element " + + "[set=" + this + "]."); + Log.logStackTrace(e); + return null; + } + } + /** * Generates a shallow copy of this object. */ diff --git a/src/java/com/threerings/presents/dobj/EntryAddedEvent.java b/src/java/com/threerings/presents/dobj/EntryAddedEvent.java index b43bfc316..7ab1fe543 100644 --- a/src/java/com/threerings/presents/dobj/EntryAddedEvent.java +++ b/src/java/com/threerings/presents/dobj/EntryAddedEvent.java @@ -1,5 +1,5 @@ // -// $Id: EntryAddedEvent.java,v 1.5 2001/10/12 00:03:03 mdb Exp $ +// $Id: EntryAddedEvent.java,v 1.6 2002/02/04 00:50:11 mdb Exp $ package com.threerings.presents.dobj; @@ -32,12 +32,17 @@ public class ElementAddedEvent extends TypedEvent * @param name the name of the attribute to which to add the specified * element. * @param elem the element to add to the set attribute. + * @param qualified whether or not the element need be qualified with + * its class when serializing (true for heterogenous sets, false for + * homogenous sets). */ - public ElementAddedEvent (int targetOid, String name, DSet.Element elem) + public ElementAddedEvent (int targetOid, String name, DSet.Element elem, + boolean qualified) { super(targetOid); _name = name; _elem = elem; + _qualified = qualified; } /** @@ -101,7 +106,7 @@ public class ElementAddedEvent extends TypedEvent { super.writeTo(out); out.writeUTF(_name); - ElementUtil.flatten(out, _elem); + ElementUtil.flatten(out, _elem, _qualified); } // documentation inherited @@ -139,4 +144,5 @@ public class ElementAddedEvent extends TypedEvent protected String _name; protected byte[] _bytes; protected DSet.Element _elem; + protected boolean _qualified; } diff --git a/src/java/com/threerings/presents/dobj/EntryUpdatedEvent.java b/src/java/com/threerings/presents/dobj/EntryUpdatedEvent.java index c6400e33a..d914992ab 100644 --- a/src/java/com/threerings/presents/dobj/EntryUpdatedEvent.java +++ b/src/java/com/threerings/presents/dobj/EntryUpdatedEvent.java @@ -1,5 +1,5 @@ // -// $Id: EntryUpdatedEvent.java,v 1.3 2001/10/12 00:03:03 mdb Exp $ +// $Id: EntryUpdatedEvent.java,v 1.4 2002/02/04 00:50:11 mdb Exp $ package com.threerings.presents.dobj; @@ -32,12 +32,17 @@ public class ElementUpdatedEvent extends TypedEvent * @param name the name of the attribute in which to update the * specified element. * @param elem the element to update. + * @param qualified whether or not the element need be qualified with + * its class when serializing (true for heterogenous sets, false for + * homogenous sets). */ - public ElementUpdatedEvent (int targetOid, String name, DSet.Element elem) + public ElementUpdatedEvent (int targetOid, String name, DSet.Element elem, + boolean qualified) { super(targetOid); _name = name; _elem = elem; + _qualified = qualified; } /** @@ -107,7 +112,7 @@ public class ElementUpdatedEvent extends TypedEvent { super.writeTo(out); out.writeUTF(_name); - ElementUtil.flatten(out, _elem); + ElementUtil.flatten(out, _elem, _qualified); } // documentation inherited @@ -145,4 +150,5 @@ public class ElementUpdatedEvent extends TypedEvent protected String _name; protected byte[] _bytes; protected DSet.Element _elem; + protected boolean _qualified; } diff --git a/src/java/com/threerings/presents/dobj/io/EntryUtil.java b/src/java/com/threerings/presents/dobj/io/EntryUtil.java index 0f7da36d2..2dda274f4 100644 --- a/src/java/com/threerings/presents/dobj/io/EntryUtil.java +++ b/src/java/com/threerings/presents/dobj/io/EntryUtil.java @@ -1,10 +1,11 @@ // -// $Id: EntryUtil.java,v 1.3 2001/10/11 04:07:52 mdb Exp $ +// $Id: EntryUtil.java,v 1.4 2002/02/04 00:50:12 mdb Exp $ package com.threerings.presents.dobj.io; import java.io.*; +import com.threerings.presents.Log; import com.threerings.presents.dobj.DSet; /** @@ -25,9 +26,13 @@ public class ElementUtil * context; uncontested syncs are pretty fast. */ public static synchronized void flatten ( - DataOutputStream out, DSet.Element elem) + DataOutputStream out, DSet.Element elem, boolean qualified) throws IOException { + // write the element classname out if requested + if (qualified) { + _dout.writeUTF(elem.getClass().getName()); + } elem.writeTo(_dout); _dout.flush(); out.writeInt(_bout.size()); @@ -44,9 +49,7 @@ public class ElementUtil throws IOException { _bin.setBytes(data); - DSet.Element elem = set.newElement(); - elem.readFrom(_din); - return elem; + return set.readElement(_din); } /**