From 5710ea9d37fa6508831806c2d7aa90e51a1a4b1a Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Tue, 18 Mar 2008 22:54:51 +0000 Subject: [PATCH] Allow scene updates to increment the version number by more than 1. git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@572 c613c5cb-e716-0410-b11b-feb51c14d237 --- .../threerings/whirled/data/SceneUpdate.java | 62 ++++++------ .../whirled/server/SceneManager.java | 3 +- .../threerings/whirled/util/UpdateList.java | 97 +++++++++---------- 3 files changed, 76 insertions(+), 86 deletions(-) diff --git a/src/java/com/threerings/whirled/data/SceneUpdate.java b/src/java/com/threerings/whirled/data/SceneUpdate.java index 16be7b0b..87651393 100644 --- a/src/java/com/threerings/whirled/data/SceneUpdate.java +++ b/src/java/com/threerings/whirled/data/SceneUpdate.java @@ -33,20 +33,18 @@ import com.threerings.util.ActionScript; import com.threerings.whirled.Log; /** - * Used to encapsulate updates to scenes in such a manner that updates can - * be stored persistently and sent to clients to update their own local - * copies of scenes. + * Used to encapsulate updates to scenes in such a manner that updates can be stored persistently + * and sent to clients to update their own local copies of scenes. */ public class SceneUpdate implements Streamable, Cloneable { /** - * Initializes this scene update such that it will operate on a scene - * with the specified target scene and version number. + * Initializes this scene update such that it will operate on a scene with the specified target + * scene and version number. * * @param targetId the id of the scene on which we are to operate. - * @param targetVersion the version of the scene on which we are to - * operate. + * @param targetVersion the version of the scene on which we are to operate. */ public void init (int targetId, int targetVersion) { @@ -71,43 +69,48 @@ public class SceneUpdate } /** - * Called to ensure that the scene is in the appropriate state prior - * to applying the update. + * Returns the amount by which this update increments the scene version. + */ + public int getVersionIncrement () + { + return 1; + } + + /** + * Called to ensure that the scene is in the appropriate state prior to applying the update. * - * @exception IllegalStateException thrown if the update cannot be - * applied to the scene because it is not in a valid state - * (appropriate previous updates were not applied, it's the wrong kind - * of scene, etc.). + * @exception IllegalStateException thrown if the update cannot be applied to the scene because + * it is not in a valid state (appropriate previous updates were not applied, it's the wrong + * kind of scene, etc.). */ public void validate (SceneModel model) throws IllegalStateException { if (model.sceneId != _targetId) { - String errmsg = "Wrong target scene, expected id " + - _targetId + " got id " + model.sceneId; + String errmsg = "Wrong target scene, expected id " + _targetId + + " got id " + model.sceneId; throw new IllegalStateException(errmsg); } if (model.version != _targetVersion) { - String errmsg = "Target scene not proper version, expected " + - _targetVersion + " got " + model.version; + String errmsg = "Target scene not proper version, expected " + _targetVersion + + " got " + model.version; throw new IllegalStateException(errmsg); } } /** - * Applies this update to the specified scene model. Derived classes - * will want to override this method and apply updates of their own, - * being sure to call super.apply. + * Applies this update to the specified scene model. Derived classes will want to override this + * method and apply updates of their own, being sure to call super.apply. */ public void apply (SceneModel model) { // increment the version; disallowing integer overflow - model.version = Math.max(_targetVersion + 1, model.version); + model.version = Math.max(_targetVersion + getVersionIncrement(), model.version); // sanity check for the amazing two billion updates if (model.version == _targetVersion) { - Log.warning("Egads! This scene has been updated two billion " + - "times [model=" + model + ", update=" + this + "]."); + Log.warning("Egads! This scene has been updated two billion times [model=" + model + + ", update=" + this + "]."); } } @@ -138,10 +141,9 @@ public class SceneUpdate } /** - * Serializes the bare representation of this instance without the scene id - * and version fields. Useful when storing updates in a database where the - * scene id and version fields are stored in separate columns and the rest - * if the representation is contained in an opaque blob. + * Serializes the bare representation of this instance without the scene id and version fields. + * Useful when storing updates in a database where the scene id and version fields are stored + * in separate columns and the rest if the representation is contained in an opaque blob. */ @ActionScript(omit=true) public void persistTo (ObjectOutputStream out) @@ -156,8 +158,7 @@ public class SceneUpdate } /** - * Unserializes this instance from the bare representation created by - * {@link #persistTo}. + * Unserializes this instance from the bare representation created by {@link #persistTo}. */ @ActionScript(omit=true) public void unpersistFrom (ObjectInputStream in) @@ -182,8 +183,7 @@ public class SceneUpdate } /** - * An extensible mechanism for generating a string representation of - * this instance. + * An extensible mechanism for generating a string representation of this instance. */ @ActionScript(name="toStringBuilder") protected void toString (StringBuilder buf) diff --git a/src/java/com/threerings/whirled/server/SceneManager.java b/src/java/com/threerings/whirled/server/SceneManager.java index e8a72e71..d4900224 100644 --- a/src/java/com/threerings/whirled/server/SceneManager.java +++ b/src/java/com/threerings/whirled/server/SceneManager.java @@ -149,8 +149,7 @@ public class SceneManager extends PlaceManager WhirledServer.invoker.postUnit(new Invoker.Unit() { public boolean invoke () { try { - _screg.getSceneRepository().applyAndRecordUpdate( - _scene.getSceneModel(), update); + _screg.getSceneRepository().applyAndRecordUpdate(_scene.getSceneModel(), update); } catch (PersistenceException pe) { Log.warning("Failed to apply scene update " + update + "."); Log.logStackTrace(pe); diff --git a/src/java/com/threerings/whirled/util/UpdateList.java b/src/java/com/threerings/whirled/util/UpdateList.java index eacdad4f..662e459d 100644 --- a/src/java/com/threerings/whirled/util/UpdateList.java +++ b/src/java/com/threerings/whirled/util/UpdateList.java @@ -21,7 +21,9 @@ package com.threerings.whirled.util; -import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Lists; import com.threerings.whirled.Log; import com.threerings.whirled.data.SceneUpdate; @@ -31,77 +33,66 @@ import com.threerings.whirled.data.SceneUpdate; */ public class UpdateList { - public UpdateList () - { - _updates = new ArrayList(); - } - /** - * Adds an update to this list. The update must follow appropriately - * the chain of updates established by the updates already in the list - * (meaning it must operate on one version higher than the most recent - * update already in the list). + * Adds an update to this list. The update must follow appropriately the chain of updates + * established by the updates already in the list (meaning it must operate on one version + * higher than the most recent update already in the list). */ public void addUpdate (SceneUpdate update) { - if (_minVersion == -1) { - // this is our first update, so we initialize our min version - _minVersion = update.getSceneVersion(); - - } else { - int gotVersion = update.getSceneVersion(); - int expVersion = _minVersion + _updates.size(); - if (gotVersion > expVersion) { - Log.warning("Update continuity broken, flushing list " + - "[got=" + update + ", expect=" + expVersion + - ", ucount=" + _updates.size() + "]."); - // flush out our old updates and start anew from here - _updates.clear(); - _minVersion = expVersion; - - } else if (gotVersion < expVersion) { - // we somehow got an update that's older than updates we - // already have? wick wick wack - String errmsg = "Invalid update version " + - "[want=" + expVersion + ", got=" + update + "]"; - throw new IllegalArgumentException(errmsg); - } + // if this is our first update, great, we let it in with no questions asked + if (_updates.isEmpty()) { + _updates.add(update); + return; } + + // otherwise make sure this update conforms to our update sequence + SceneUpdate last = _updates.get(_updates.size()-1); + int expVersion = last.getSceneVersion() + last.getVersionIncrement(); + int gotVersion = update.getSceneVersion(); + if (gotVersion > expVersion) { + Log.warning("Update continuity broken, flushing list [got=" + update + + ", expect=" + expVersion + ", ucount=" + _updates.size() + "]."); + _updates.clear(); // flush out our old updates, fall through and add this one + + } else if (gotVersion < expVersion) { + // we somehow got an update that's older than updates we already have? + String errmsg = "Invalid update version [want=" + expVersion + ", got=" + update + "]"; + throw new IllegalArgumentException(errmsg); + } + _updates.add(update); } /** - * Returns all of the updates that should be applied to a scene with - * the specified version to bring it up to date. null is - * returned if the scene's version is older than the oldest update in - * our list, in which case it cannot be brought up to date by applying - * updates from this list. + * Returns all of the updates that should be applied to a scene with the specified version to + * bring it up to date. null is returned if the scene's version is older than the + * oldest update in our list, in which case it cannot be brought up to date by applying updates + * from this list. */ public SceneUpdate[] getUpdates (int fromVersion) { - if (_minVersion == -1 || fromVersion < _minVersion) { - return null; + List updates = Lists.newArrayList(); + for (SceneUpdate update : _updates) { + if (update.getSceneVersion() >= fromVersion) { + updates.add(update); + } } - - int offset = fromVersion - _minVersion; - int ucount = _updates.size() - offset; - SceneUpdate[] updates = new SceneUpdate[ucount]; - for (int ii = 0; ii < ucount; ii++) { - updates[ii] = (SceneUpdate)_updates.get(ii+offset); - } - return updates; + return updates.toArray(new SceneUpdate[updates.size()]); } /** - * Returns true if the supplied actual scene version is in accordance - * with the updates contained in this list. + * Returns true if the supplied actual scene version is in accordance with the updates + * contained in this list. */ public boolean validate (int sceneVersion) { - return ((_minVersion == -1) || // we have no updates - (_minVersion + _updates.size() == sceneVersion)); + if (_updates.size() == 0) { + return true; + } + SceneUpdate last = _updates.get(_updates.size()-1); + return sceneVersion == (last.getSceneVersion() + last.getVersionIncrement()); } - protected ArrayList _updates; - protected int _minVersion = -1; + protected List _updates = Lists.newArrayList(); }